@memberjunction/ng-conversations 6.2.0-edge.3 → 6.2.0-edge.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/README.md +4 -7
  2. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  3. package/dist/lib/components/collection/collection-view.component.js +1 -0
  4. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  5. package/dist/lib/components/composer/ai-composer.component.d.ts +14 -2
  6. package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
  7. package/dist/lib/components/composer/ai-composer.component.js +35 -4
  8. package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
  9. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +588 -51
  10. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  11. package/dist/lib/components/conversation/conversation-chat-area.component.js +2654 -665
  12. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  13. package/dist/lib/components/conversation/forks-popover.component.d.ts +37 -0
  14. package/dist/lib/components/conversation/forks-popover.component.d.ts.map +1 -0
  15. package/dist/lib/components/conversation/forks-popover.component.js +164 -0
  16. package/dist/lib/components/conversation/forks-popover.component.js.map +1 -0
  17. package/dist/lib/components/export/export-modal.component.d.ts +7 -2
  18. package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
  19. package/dist/lib/components/export/export-modal.component.js +16 -3
  20. package/dist/lib/components/export/export-modal.component.js.map +1 -1
  21. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
  22. package/dist/lib/components/message/conversation-message-rating.component.js +11 -9
  23. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
  24. package/dist/lib/components/message/message-input.component.d.ts +96 -11
  25. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  26. package/dist/lib/components/message/message-input.component.js +244 -103
  27. package/dist/lib/components/message/message-input.component.js.map +1 -1
  28. package/dist/lib/components/message/message-item.component.d.ts +171 -4
  29. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  30. package/dist/lib/components/message/message-item.component.js +899 -298
  31. package/dist/lib/components/message/message-item.component.js.map +1 -1
  32. package/dist/lib/components/message/message-list.component.d.ts +82 -21
  33. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  34. package/dist/lib/components/message/message-list.component.js +299 -52
  35. package/dist/lib/components/message/message-list.component.js.map +1 -1
  36. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts +34 -0
  37. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts.map +1 -0
  38. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js +75 -0
  39. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js.map +1 -0
  40. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts +80 -0
  41. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts.map +1 -0
  42. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js +202 -0
  43. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js.map +1 -0
  44. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts +45 -0
  45. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts.map +1 -0
  46. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js +123 -0
  47. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js.map +1 -0
  48. package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts +90 -0
  49. package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts.map +1 -0
  50. package/dist/lib/components/realtime/capture/realtime-capture-channel.js +223 -0
  51. package/dist/lib/components/realtime/capture/realtime-capture-channel.js.map +1 -0
  52. package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts +98 -0
  53. package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts.map +1 -0
  54. package/dist/lib/components/realtime/capture/realtime-capture-model.js +161 -0
  55. package/dist/lib/components/realtime/capture/realtime-capture-model.js.map +1 -0
  56. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts +48 -0
  57. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts.map +1 -0
  58. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js +205 -0
  59. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js.map +1 -0
  60. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +19 -2
  61. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
  62. package/dist/lib/components/realtime/channels/client-context-channel.js +83 -9
  63. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
  64. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +30 -9
  65. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
  66. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +78 -14
  67. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
  68. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts +71 -0
  69. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map +1 -0
  70. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js +259 -0
  71. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map +1 -0
  72. package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts +129 -0
  73. package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts.map +1 -0
  74. package/dist/lib/components/realtime/identity-verification/identity-verification-model.js +373 -0
  75. package/dist/lib/components/realtime/identity-verification/identity-verification-model.js.map +1 -0
  76. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts +77 -0
  77. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts.map +1 -0
  78. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js +420 -0
  79. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js.map +1 -0
  80. package/dist/lib/components/realtime/interactive-component/component-contract.d.ts +83 -0
  81. package/dist/lib/components/realtime/interactive-component/component-contract.d.ts.map +1 -0
  82. package/dist/lib/components/realtime/interactive-component/component-contract.js +292 -0
  83. package/dist/lib/components/realtime/interactive-component/component-contract.js.map +1 -0
  84. package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts +39 -0
  85. package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts.map +1 -0
  86. package/dist/lib/components/realtime/interactive-component/component-data-state.js +152 -0
  87. package/dist/lib/components/realtime/interactive-component/component-data-state.js.map +1 -0
  88. package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts +109 -0
  89. package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts.map +1 -0
  90. package/dist/lib/components/realtime/interactive-component/component-instance-engine.js +146 -0
  91. package/dist/lib/components/realtime/interactive-component/component-instance-engine.js.map +1 -0
  92. package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts +19 -0
  93. package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts.map +1 -0
  94. package/dist/lib/components/realtime/interactive-component/component-spec-content.js +39 -0
  95. package/dist/lib/components/realtime/interactive-component/component-spec-content.js.map +1 -0
  96. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts +183 -0
  97. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts.map +1 -0
  98. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js +761 -0
  99. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js.map +1 -0
  100. package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts +25 -0
  101. package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts.map +1 -0
  102. package/dist/lib/components/realtime/interactive-component/interactive-component-config.js +57 -0
  103. package/dist/lib/components/realtime/interactive-component/interactive-component-config.js.map +1 -0
  104. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts +40 -0
  105. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts.map +1 -0
  106. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js +97 -0
  107. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js.map +1 -0
  108. package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts +144 -0
  109. package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts.map +1 -0
  110. package/dist/lib/components/realtime/interactive-component/interactive-component-types.js +57 -0
  111. package/dist/lib/components/realtime/interactive-component/interactive-component-types.js.map +1 -0
  112. package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts +36 -0
  113. package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts.map +1 -0
  114. package/dist/lib/components/realtime/interactive-component/react-component-handle.js +55 -0
  115. package/dist/lib/components/realtime/interactive-component/react-component-handle.js.map +1 -0
  116. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts +55 -0
  117. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts.map +1 -0
  118. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js +210 -0
  119. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js.map +1 -0
  120. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts +32 -0
  121. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts.map +1 -0
  122. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +90 -0
  123. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -0
  124. package/dist/lib/components/realtime/media/media-channel.d.ts +7 -0
  125. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  126. package/dist/lib/components/realtime/media/media-channel.js +28 -1
  127. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  128. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +8 -1
  129. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  130. package/dist/lib/components/realtime/realtime-agent-banner.component.js +89 -71
  131. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  132. package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts +21 -0
  133. package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts.map +1 -0
  134. package/dist/lib/components/realtime/realtime-agent-orb.component.js +49 -0
  135. package/dist/lib/components/realtime/realtime-agent-orb.component.js.map +1 -0
  136. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +44 -11
  137. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
  138. package/dist/lib/components/realtime/realtime-agent-picker.component.js +162 -50
  139. package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
  140. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +8 -2
  141. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
  142. package/dist/lib/components/realtime/realtime-audio-visuals.js +14 -18
  143. package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
  144. package/dist/lib/components/realtime/realtime-composer.component.d.ts +42 -2
  145. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  146. package/dist/lib/components/realtime/realtime-composer.component.js +137 -102
  147. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  148. package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts +71 -0
  149. package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts.map +1 -0
  150. package/dist/lib/components/realtime/realtime-perception-chip.component.js +221 -0
  151. package/dist/lib/components/realtime/realtime-perception-chip.component.js.map +1 -0
  152. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +264 -22
  153. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  154. package/dist/lib/components/realtime/realtime-session-overlay.component.js +851 -135
  155. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  156. package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts +14 -0
  157. package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts.map +1 -0
  158. package/dist/lib/components/realtime/realtime-surface-placement-prefs.js +14 -0
  159. package/dist/lib/components/realtime/realtime-surface-placement-prefs.js.map +1 -0
  160. package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts +74 -0
  161. package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts.map +1 -0
  162. package/dist/lib/components/realtime/realtime-surface-stage.model.js +171 -0
  163. package/dist/lib/components/realtime/realtime-surface-stage.model.js.map +1 -0
  164. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +71 -13
  165. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  166. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +232 -73
  167. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  168. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +5 -0
  169. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  170. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +8 -0
  171. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  172. package/dist/lib/components/realtime/realtime-ui-config.d.ts +12 -2
  173. package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
  174. package/dist/lib/components/realtime/realtime-ui-config.js +5 -1
  175. package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
  176. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +10 -1
  177. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  178. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +42 -2
  179. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  180. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +20 -3
  181. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
  182. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +44 -10
  183. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
  184. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +28 -44
  185. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  186. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +76 -162
  187. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  188. package/dist/lib/components/search/search-panel.component.d.ts +2 -0
  189. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  190. package/dist/lib/components/search/search-panel.component.js +25 -12
  191. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  192. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +22 -31
  193. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  194. package/dist/lib/components/workspace/conversation-workspace.component.js +50 -63
  195. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  196. package/dist/lib/conversations.module.d.ts +30 -29
  197. package/dist/lib/conversations.module.d.ts.map +1 -1
  198. package/dist/lib/conversations.module.js +27 -5
  199. package/dist/lib/conversations.module.js.map +1 -1
  200. package/dist/lib/events/chat-events.d.ts +25 -0
  201. package/dist/lib/events/chat-events.d.ts.map +1 -1
  202. package/dist/lib/events/chat-events.js +36 -0
  203. package/dist/lib/events/chat-events.js.map +1 -1
  204. package/dist/lib/models/agent-turn.model.d.ts +5 -0
  205. package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
  206. package/dist/lib/models/agent-turn.model.js.map +1 -1
  207. package/dist/lib/services/agent-state.service.d.ts +34 -8
  208. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  209. package/dist/lib/services/agent-state.service.js +82 -29
  210. package/dist/lib/services/agent-state.service.js.map +1 -1
  211. package/dist/lib/services/artifact-state.service.d.ts +0 -9
  212. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  213. package/dist/lib/services/artifact-state.service.js +1 -32
  214. package/dist/lib/services/artifact-state.service.js.map +1 -1
  215. package/dist/lib/services/browser-realtime-media-host.d.ts +12 -0
  216. package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
  217. package/dist/lib/services/browser-realtime-media-host.js +19 -0
  218. package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
  219. package/dist/lib/services/browser-recording-unload-guard.d.ts +30 -0
  220. package/dist/lib/services/browser-recording-unload-guard.d.ts.map +1 -0
  221. package/dist/lib/services/browser-recording-unload-guard.js +43 -0
  222. package/dist/lib/services/browser-recording-unload-guard.js.map +1 -0
  223. package/dist/lib/services/conversation-agent.service.d.ts +35 -11
  224. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  225. package/dist/lib/services/conversation-agent.service.js +65 -20
  226. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  227. package/dist/lib/services/conversation-detail-window.store.d.ts +22 -4
  228. package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
  229. package/dist/lib/services/conversation-detail-window.store.js +50 -9
  230. package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
  231. package/dist/lib/services/conversation-naming.d.ts +72 -22
  232. package/dist/lib/services/conversation-naming.d.ts.map +1 -1
  233. package/dist/lib/services/conversation-naming.js +84 -10
  234. package/dist/lib/services/conversation-naming.js.map +1 -1
  235. package/dist/lib/services/data-cache.service.d.ts +13 -5
  236. package/dist/lib/services/data-cache.service.d.ts.map +1 -1
  237. package/dist/lib/services/data-cache.service.js +39 -19
  238. package/dist/lib/services/data-cache.service.js.map +1 -1
  239. package/dist/lib/services/export.service.d.ts +26 -9
  240. package/dist/lib/services/export.service.d.ts.map +1 -1
  241. package/dist/lib/services/export.service.js +61 -18
  242. package/dist/lib/services/export.service.js.map +1 -1
  243. package/dist/lib/services/realtime-audio-recorder.d.ts +33 -5
  244. package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
  245. package/dist/lib/services/realtime-audio-recorder.js +71 -11
  246. package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
  247. package/dist/lib/services/realtime-pairing.d.ts +10 -5
  248. package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
  249. package/dist/lib/services/realtime-pairing.js +15 -6
  250. package/dist/lib/services/realtime-pairing.js.map +1 -1
  251. package/dist/lib/services/realtime-session.service.d.ts +3 -2
  252. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  253. package/dist/lib/services/realtime-session.service.js +7 -2
  254. package/dist/lib/services/realtime-session.service.js.map +1 -1
  255. package/dist/lib/services/search.service.d.ts +7 -2
  256. package/dist/lib/services/search.service.d.ts.map +1 -1
  257. package/dist/lib/services/search.service.js +13 -4
  258. package/dist/lib/services/search.service.js.map +1 -1
  259. package/dist/lib/utils/conversation-branching.d.ts +4 -0
  260. package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
  261. package/dist/lib/utils/conversation-branching.js +5 -0
  262. package/dist/lib/utils/conversation-branching.js.map +1 -0
  263. package/dist/lib/utils/conversation-forks.d.ts +315 -0
  264. package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
  265. package/dist/lib/utils/conversation-forks.js +456 -0
  266. package/dist/lib/utils/conversation-forks.js.map +1 -0
  267. package/dist/public-api.d.ts +23 -1
  268. package/dist/public-api.d.ts.map +1 -1
  269. package/dist/public-api.js +30 -1
  270. package/dist/public-api.js.map +1 -1
  271. package/package.json +37 -33
  272. package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
  273. package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
  274. package/dist/lib/components/thread/thread-panel.component.js +0 -440
  275. package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-naming.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Shared conversation auto-naming helper — extracted from the message\n * input's first-message naming flow so BOTH chat paths use one implementation:\n *\n * - **Regular chat**: the composer names a brand-new conversation from its first\n * user message (the original behavior, now delegated here).\n * - **Realtime sessions**: a voice call that created a fresh conversation names it\n * from the first user utterance when the call ends.\n *\n * The naming itself is DB-driven: the `Name Conversation` AI prompt runs through the\n * GraphQL AI client (same path agents use) with a timeout guard; the parsed\n * `{ name, description }` is saved through {@link ConversationEngine.SaveConversation},\n * which updates the engine's cached conversation list in place (the sidebar reacts\n * through the engine's observables). Failures are logged and return `null` — naming is\n * always best-effort background work that must never affect the user experience.\n */\nimport { UserInfo } from '@memberjunction/core';\nimport { CleanAndParseJSON } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { GraphQLDataProvider, GraphQLAIClient } from '@memberjunction/graphql-dataprovider';\nimport { ConversationEngine } from '@memberjunction/core-entities';\n\n/** The applied result of a successful auto-naming run. */\nexport interface ConversationNameResult {\n /** The generated conversation name (already saved). */\n Name: string;\n /** The generated description (already saved; empty string when the prompt omitted it). */\n Description: string;\n}\n\n/** Options for {@link GenerateAndApplyConversationName}. */\nexport interface GenerateConversationNameOptions {\n /** The conversation to name (must exist; the caller owns membership checks). */\n ConversationId: string;\n /**\n * The text the name is derived from — the first user message (regular chat) or the\n * first spoken user utterance (realtime). Callers strip mentions/markup first.\n */\n MessageText: string;\n /** The GraphQL provider the AI client runs over. */\n Provider: GraphQLDataProvider;\n /** The acting user (threaded into the conversation save). */\n CurrentUser: UserInfo;\n /** Abort guard for the prompt run. Default 30s — the conversation keeps its default name on timeout. */\n TimeoutMs?: number;\n /**\n * Test seam: overrides the prompt execution. Production leaves this undefined and the\n * helper runs the `Name Conversation` prompt via {@link GraphQLAIClient.RunAIPrompt}.\n */\n RunPrompt?: (promptId: string, messageText: string) => Promise<{ success: boolean; parsedResult?: unknown; output?: string } | null>;\n}\n\n/** The seeded name of the AI prompt that generates conversation names. */\nexport const NAME_CONVERSATION_PROMPT = 'Name Conversation';\n\n/**\n * Generates a name + description for a conversation from its first message and SAVES it\n * (DB + engine cache) — the single naming implementation shared by the regular composer\n * and the realtime session path.\n *\n * @returns The applied `{ Name, Description }`, or `null` when naming was skipped/failed\n * (missing prompt, provider unavailable, timeout, unparseable output, save failure) —\n * the conversation keeps its current name in every null case.\n */\nexport async function GenerateAndApplyConversationName(\n options: GenerateConversationNameOptions\n): Promise<ConversationNameResult | null> {\n try {\n await AIEngineBase.Instance.Config(false);\n const prompt = AIEngineBase.Instance.Prompts.find(pr => pr.Name === NAME_CONVERSATION_PROMPT);\n if (!prompt) {\n console.warn(`⚠️ ${NAME_CONVERSATION_PROMPT} prompt not found`);\n return null;\n }\n if (!options.Provider) {\n console.warn('⚠️ GraphQLDataProvider not available for conversation naming');\n return null;\n }\n\n const run = options.RunPrompt\n ?? ((promptId: string, messageText: string) =>\n new GraphQLAIClient(options.Provider).RunAIPrompt({\n promptId,\n messages: [{ role: 'user', content: messageText }]\n }));\n\n const timeoutMs = options.TimeoutMs ?? 30000;\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(`Conversation naming timed out after ${Math.round(timeoutMs / 1000)} seconds`)), timeoutMs);\n });\n\n const result = await Promise.race([run(prompt.ID, options.MessageText), timeoutPromise]);\n if (!result || !result.success || (!result.parsedResult && !result.output)) {\n return null;\n }\n\n // parsedResult preferred; CleanAndParseJSON tolerates ```json fences in raw output.\n const parsed = (result.parsedResult ?? (result.output ? CleanAndParseJSON(result.output) : null)) as\n | { name?: string; description?: string }\n | null;\n if (!parsed?.name) {\n return null;\n }\n\n const saved = await ConversationEngine.Instance.SaveConversation(\n options.ConversationId,\n { Name: parsed.name, Description: parsed.description || '' },\n options.CurrentUser\n );\n if (!saved) {\n console.warn('⚠️ Conversation naming generated a name but the save failed');\n return null;\n }\n return { Name: parsed.name, Description: parsed.description || '' };\n } catch (error) {\n console.warn('⚠️ Conversation naming failed (conversation keeps its default name):', error);\n return null;\n }\n}\n"]}
1
+ {"version":3,"file":"conversation-naming.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Shared conversation auto-naming helper — extracted from the message\n * input's first-message naming flow so BOTH chat paths use one implementation:\n *\n * - **Regular chat**: the composer names a brand-new conversation from its first\n * user message (the original behavior, now delegated here).\n * - **Realtime sessions**: a voice call that created a fresh conversation names it\n * from the first user utterance when the call ends.\n * - **Forks**: a Fork or Edit fork is named from the first message sent into it, when it\n * still has no name ({@link GenerateAndApplyForkName}).\n *\n * The naming itself is DB-driven: the `Name Conversation` AI prompt runs through the\n * GraphQL AI client (same path agents use) with a timeout guard ({@link GenerateConversationName}).\n * A conversation's parsed `{ name, description }` is saved through\n * {@link ConversationEngine.SaveConversation}, which updates the engine's cached conversation\n * list in place (the sidebar reacts through the engine's observables); a fork's name is saved\n * on its `MJ: Conversation Branches` row. Failures are logged and return `null` — naming is\n * always best-effort background work that must never affect the user experience.\n */\nimport { IMetadataProvider, UserInfo } from '@memberjunction/core';\nimport { CleanAndParseJSON } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { GraphQLDataProvider, GraphQLAIClient, type RunAIPromptResult } from '@memberjunction/graphql-dataprovider';\nimport { ConversationEngine, type MJConversationBranchEntity } from '@memberjunction/core-entities';\n\n/** The result of a successful naming run. */\nexport interface ConversationNameResult {\n /** The generated name, trimmed. */\n Name: string;\n /** The generated description; empty string when the prompt omitted it. */\n Description: string;\n}\n\n/** The prompt runner {@link GenerateConversationName} calls; a test seam for the GraphQL AI client. */\nexport type NamePromptRunner = (\n promptId: string,\n messageText: string\n) => Promise<Pick<RunAIPromptResult, 'success' | 'parsedResult' | 'output'> | null>;\n\n/** Options for {@link GenerateConversationName}. */\nexport interface GenerateNameOptions {\n /**\n * The text the name is derived from — the first user message (regular chat and forks) or the\n * first spoken user utterance (realtime). Callers strip mentions/markup first.\n */\n MessageText: string;\n /** The GraphQL provider the AI client runs over. */\n Provider: GraphQLDataProvider;\n /** Abort guard for the prompt run. Default 30s — the target keeps its current name on timeout. */\n TimeoutMs?: number;\n /**\n * Test seam: overrides the prompt execution. Production leaves this undefined and the\n * helper runs the `Name Conversation` prompt via {@link GraphQLAIClient.RunAIPrompt}.\n */\n RunPrompt?: NamePromptRunner;\n}\n\n/** Options for {@link GenerateAndApplyConversationName}. */\nexport interface GenerateConversationNameOptions extends GenerateNameOptions {\n /** The conversation to name (must exist; the caller owns membership checks). */\n ConversationId: string;\n /** The acting user (threaded into the conversation save). */\n CurrentUser: UserInfo;\n}\n\n/** Options for {@link GenerateAndApplyForkName}. */\nexport interface GenerateForkNameOptions extends GenerateNameOptions {\n /** The fork (`MJ: Conversation Branches` row) to name. */\n ForkId: string;\n /** The acting user; the branch entity's write rule applies to the save. */\n CurrentUser: UserInfo;\n}\n\n/** The seeded name of the AI prompt that generates conversation names. */\nexport const NAME_CONVERSATION_PROMPT = 'Name Conversation';\n\n/** Longest fork name the `MJ: Conversation Branches` Name field holds. */\nexport const MAX_FORK_NAME_LENGTH = 255;\n\n/**\n * Runs the `Name Conversation` prompt on a message and parses its `{ name, description }`. Saves nothing.\n *\n * @returns The generated `{ Name, Description }`, or `null` when the prompt is missing, the provider is\n * unavailable, the run fails or times out, or the output has no name. Failures are logged.\n */\nexport async function GenerateConversationName(options: GenerateNameOptions): Promise<ConversationNameResult | null> {\n try {\n await AIEngineBase.Instance.Config(false);\n const prompt = AIEngineBase.Instance.Prompts.find(pr => pr.Name === NAME_CONVERSATION_PROMPT);\n if (!prompt) {\n console.warn(`⚠️ ${NAME_CONVERSATION_PROMPT} prompt not found`);\n return null;\n }\n if (!options.Provider) {\n console.warn('⚠️ GraphQLDataProvider not available for conversation naming');\n return null;\n }\n\n const run: NamePromptRunner = options.RunPrompt\n ?? ((promptId: string, messageText: string) =>\n new GraphQLAIClient(options.Provider).RunAIPrompt({\n promptId,\n messages: [{ role: 'user', content: messageText }]\n }));\n\n const timeoutMs = options.TimeoutMs ?? 30000;\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(`Conversation naming timed out after ${Math.round(timeoutMs / 1000)} seconds`)), timeoutMs);\n });\n\n const result = await Promise.race([run(prompt.ID, options.MessageText), timeoutPromise]);\n if (!result || !result.success || (!result.parsedResult && !result.output)) {\n return null;\n }\n\n // parsedResult preferred; CleanAndParseJSON tolerates ```json fences in raw output.\n const parsed = (result.parsedResult ?? (result.output ? CleanAndParseJSON(result.output) : null)) as\n | { name?: string; description?: string }\n | null;\n const name = typeof parsed?.name === 'string' ? parsed.name.trim() : '';\n if (!name) {\n return null;\n }\n return { Name: name, Description: parsed?.description || '' };\n } catch (error) {\n console.warn('⚠️ Conversation naming failed (the current name stays):', error);\n return null;\n }\n}\n\n/**\n * Generates a name + description for a conversation from its first message and SAVES it\n * (DB + engine cache) — the single naming implementation shared by the regular composer\n * and the realtime session path.\n *\n * @returns The applied `{ Name, Description }`, or `null` when naming was skipped/failed\n * (missing prompt, provider unavailable, timeout, unparseable output, save failure) —\n * the conversation keeps its current name in every null case.\n */\nexport async function GenerateAndApplyConversationName(\n options: GenerateConversationNameOptions\n): Promise<ConversationNameResult | null> {\n const generated = await GenerateConversationName(options);\n if (!generated) {\n return null;\n }\n try {\n const saved = await ConversationEngine.Instance.SaveConversation(\n options.ConversationId,\n { Name: generated.Name, Description: generated.Description },\n options.CurrentUser\n );\n if (!saved) {\n console.warn('⚠️ Conversation naming generated a name but the save failed');\n return null;\n }\n return generated;\n } catch (error) {\n console.warn('⚠️ Conversation naming failed (conversation keeps its default name):', error);\n return null;\n }\n}\n\n/** Options for {@link SaveForkName}. */\nexport interface SaveForkNameOptions {\n /** The fork (`MJ: Conversation Branches` row) to name. */\n ForkId: string;\n /** The new name; null or blank clears it, so the default label shows. Cut to {@link MAX_FORK_NAME_LENGTH}. */\n Name: string | null;\n /** The provider the branch entity is read and saved through. */\n Provider: IMetadataProvider;\n /** The acting user; the branch entity's write rule applies. */\n CurrentUser: UserInfo;\n /** When true, saves nothing if the row read fresh already has a name. */\n OnlyIfUnnamed?: boolean;\n}\n\n/**\n * Saves a fork's Name through the `MJ: Conversation Branches` entity, after reading the row fresh.\n *\n * @returns true when the name was saved; false when the row cannot be read, when `OnlyIfUnnamed` is\n * set and the row has a name, or when the save fails (logged).\n * @throws when the entity read or save throws\n */\nexport async function SaveForkName(options: SaveForkNameOptions): Promise<boolean> {\n const fork = await options.Provider.GetEntityObject<MJConversationBranchEntity>('MJ: Conversation Branches', options.CurrentUser);\n if (!(await fork.Load(options.ForkId))) {\n console.warn(`⚠️ Could not read fork ${options.ForkId} to save its name`);\n return false;\n }\n if (options.OnlyIfUnnamed && fork.Name?.trim()) {\n return false;\n }\n const name = options.Name?.trim().slice(0, MAX_FORK_NAME_LENGTH).trim();\n fork.Name = name ? name : null;\n if (!(await fork.Save())) {\n console.warn(`⚠️ Could not save the name of fork ${options.ForkId}: ${fork.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n return false;\n }\n return true;\n}\n\n/**\n * Names a fork from its first message: runs the `Name Conversation` prompt ({@link GenerateConversationName})\n * and saves the name as the fork's Name only when the fork, read fresh right before the save, still has\n * no name, so a person's rename wins.\n *\n * @returns The saved name, or `null` when naming failed, the fork already has a name, or the save failed.\n * Failures are logged.\n */\nexport async function GenerateAndApplyForkName(options: GenerateForkNameOptions): Promise<string | null> {\n const generated = await GenerateConversationName(options);\n if (!generated) {\n return null;\n }\n try {\n const saved = await SaveForkName({\n ForkId: options.ForkId,\n Name: generated.Name,\n Provider: options.Provider,\n CurrentUser: options.CurrentUser,\n OnlyIfUnnamed: true,\n });\n return saved ? generated.Name.slice(0, MAX_FORK_NAME_LENGTH).trim() : null;\n } catch (error) {\n console.warn(`⚠️ Fork naming failed (fork ${options.ForkId} keeps its current name):`, error);\n return null;\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';
1
+ import { ConversationScope, MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';
2
2
  import { UserInfo, IMetadataProvider } from '@memberjunction/core';
3
3
  import * as i0 from "@angular/core";
4
4
  /**
@@ -72,15 +72,23 @@ export declare class DataCacheService {
72
72
  /** @deprecated Use {@link CreateConversationDetail}. */
73
73
  createConversationDetail(currentUser: UserInfo): Promise<MJConversationDetailEntity>;
74
74
  /**
75
- * Load all ConversationDetail entities for a conversation and cache them
76
- * Used when loading a conversation's message history
75
+ * Load the ConversationDetail entities of one scope of a conversation (Main, or one fork's
76
+ * path) that no rerun replaced, and cache them
77
77
  * @param conversationId The conversation ID
78
78
  * @param currentUser User context
79
+ * @param scope The rows to read; Main when omitted
79
80
  * @returns Array of MJConversationDetailEntity objects
81
+ * @throws when the scope belongs to another conversation
80
82
  */
81
- LoadConversationDetails(conversationId: string, currentUser: UserInfo): Promise<MJConversationDetailEntity[]>;
83
+ LoadConversationDetails(conversationId: string, currentUser: UserInfo, scope?: ConversationScope): Promise<MJConversationDetailEntity[]>;
84
+ /**
85
+ * Adds loaded details to the cache, replacing any cached detail with the same ID in place.
86
+ * Positions are indexed once up front: the cache spans every loaded conversation, so searching
87
+ * it for each loaded detail grew with both.
88
+ */
89
+ private upsertCachedDetails;
82
90
  /** @deprecated Use {@link LoadConversationDetails}. */
83
- loadConversationDetails(conversationId: string, currentUser: UserInfo): Promise<MJConversationDetailEntity[]>;
91
+ loadConversationDetails(conversationId: string, currentUser: UserInfo, scope?: ConversationScope): Promise<MJConversationDetailEntity[]>;
84
92
  /**
85
93
  * Get all cached ConversationDetail entities for a conversation (no DB call)
86
94
  * @param conversationId The conversation ID
@@ -1 +1 @@
1
- {"version":3,"file":"data-cache.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/data-cache.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-cache.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/data-cache.service.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { Injectable } from '@angular/core';
2
+ import { ConversationEngine } from '@memberjunction/core-entities';
2
3
  import { Metadata, RunView } from '@memberjunction/core';
3
- import { UUIDsEqual } from '@memberjunction/global';
4
+ import { UUIDMap, UUIDsEqual } from '@memberjunction/global';
4
5
  import * as i0 from "@angular/core";
5
6
  /**
6
7
  * Global singleton cache for conversation-related entities.
@@ -148,46 +149,65 @@ export class DataCacheService {
148
149
  return this.CreateConversationDetail(currentUser);
149
150
  }
150
151
  /**
151
- * Load all ConversationDetail entities for a conversation and cache them
152
- * Used when loading a conversation's message history
152
+ * Load the ConversationDetail entities of one scope of a conversation (Main, or one fork's
153
+ * path) that no rerun replaced, and cache them
153
154
  * @param conversationId The conversation ID
154
155
  * @param currentUser User context
156
+ * @param scope The rows to read; Main when omitted
155
157
  * @returns Array of MJConversationDetailEntity objects
158
+ * @throws when the scope belongs to another conversation
156
159
  */
157
- async LoadConversationDetails(conversationId, currentUser) {
160
+ async LoadConversationDetails(conversationId, currentUser, scope) {
161
+ if (scope && !UUIDsEqual(scope.ConversationID, conversationId)) {
162
+ throw new Error(`Conversation ${conversationId} cannot be read with the scope of conversation ${scope.ConversationID}`);
163
+ }
164
+ const resolved = scope ?? ConversationEngine.TrunkScope(conversationId);
158
165
  const timestamp = new Date().toISOString();
159
166
  console.log(`[${timestamp}] 💾 DataCacheService.loadConversationDetails - Loading messages for conversation ${conversationId}`);
160
167
  const rv = RunView.FromMetadataProvider(this.Provider);
161
168
  console.log(`[${timestamp}] 💾 DataCacheService - Executing RunView for Conversation Details`);
162
169
  const result = await rv.RunView({
163
170
  EntityName: 'MJ: Conversation Details',
164
- ExtraFilter: `ConversationID='${conversationId}'`,
171
+ ExtraFilter: ConversationEngine.LiveRowsFilter(ConversationEngine.ScopeFilter(resolved)),
165
172
  OrderBy: '__mj_CreatedAt ASC',
166
173
  ResultType: 'entity_object'
167
174
  }, currentUser);
168
175
  if (result.Success) {
169
176
  const details = result.Results || [];
170
177
  console.log(`[${timestamp}] 💾 DataCacheService - Loaded ${details.length} message(s) for conversation ${conversationId}`);
171
- // Add all to cache (avoid duplicates by checking ID)
172
- for (const detail of details) {
173
- const existingIndex = this.conversationDetails.findIndex(d => UUIDsEqual(d.ID, detail.ID));
174
- if (existingIndex >= 0) {
175
- // Replace existing (ensures we keep the same object reference)
176
- this.conversationDetails[existingIndex] = detail;
177
- }
178
- else {
179
- // Add new
180
- this.conversationDetails.push(detail);
181
- }
182
- }
178
+ this.upsertCachedDetails(details);
183
179
  return details;
184
180
  }
185
181
  console.log(`[${timestamp}] 💾 DataCacheService - Failed to load messages for conversation ${conversationId}`);
186
182
  return [];
187
183
  }
184
+ /**
185
+ * Adds loaded details to the cache, replacing any cached detail with the same ID in place.
186
+ * Positions are indexed once up front: the cache spans every loaded conversation, so searching
187
+ * it for each loaded detail grew with both.
188
+ */
189
+ upsertCachedDetails(details) {
190
+ const positionByID = new UUIDMap();
191
+ this.conversationDetails.forEach((d, i) => {
192
+ if (!positionByID.Has(d.ID))
193
+ positionByID.Set(d.ID, i);
194
+ });
195
+ for (const detail of details) {
196
+ const existingIndex = positionByID.Get(detail.ID);
197
+ if (existingIndex !== undefined) {
198
+ // Replace existing (ensures we keep the same object reference)
199
+ this.conversationDetails[existingIndex] = detail;
200
+ }
201
+ else {
202
+ // Add new
203
+ positionByID.Set(detail.ID, this.conversationDetails.length);
204
+ this.conversationDetails.push(detail);
205
+ }
206
+ }
207
+ }
188
208
  /** @deprecated Use {@link LoadConversationDetails}. */
189
- async loadConversationDetails(conversationId, currentUser) {
190
- return this.LoadConversationDetails(conversationId, currentUser);
209
+ async loadConversationDetails(conversationId, currentUser, scope) {
210
+ return this.LoadConversationDetails(conversationId, currentUser, scope);
191
211
  }
192
212
  /**
193
213
  * Get all cached ConversationDetail entities for a conversation (no DB call)
@@ -1 +1 @@
1
- {"version":3,"file":"data-cache.service.js","sourceRoot":"","sources":["../../../src/lib/services/data-cache.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';\nimport { Metadata, UserInfo, BaseEntity, RunView, IMetadataProvider } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Global singleton cache for conversation-related entities.\n * Maintains single instances of entities to prevent race conditions and ensure\n * all components see the same object state.\n *\n * Pattern: Instead of creating new entity instances with GetEntityObject() everywhere,\n * request entities from this cache. The cache returns the same instance each time,\n * so when one component updates entity.Status = 'Complete', all other components\n * see that change immediately without needing to reload from the database.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class DataCacheService {\n // Separate arrays for each entity type\n private conversations: MJConversationEntity[] = [];\n private conversationDetails: MJConversationDetailEntity[] = [];\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 // MJConversationEntity Methods\n // =============================================================================\n\n /**\n * Get a MJConversationEntity by ID from cache, or load it if not cached\n * @param id The conversation ID\n * @param currentUser User context for loading\n * @returns The cached or loaded MJConversationEntity, or null if not found\n */\n async GetConversation(id: string, currentUser: UserInfo): Promise<MJConversationEntity | null> {\n // Check cache first\n const cached = this.conversations.find(c => UUIDsEqual(c.ID, id));\n if (cached) {\n return cached;\n }\n\n // Not in cache - load from DB\n const md = this.Provider;\n const conversation = await md.GetEntityObject<MJConversationEntity>('MJ: Conversations', currentUser);\n const loaded = await conversation.Load(id);\n\n if (loaded) {\n // Add to cache\n this.conversations.push(conversation);\n return conversation;\n }\n\n return null;\n }\n\n /** @deprecated Use {@link GetConversation}. */\n async getConversation(id: string, currentUser: UserInfo): Promise<MJConversationEntity | null> {\n return this.GetConversation(id, currentUser);\n }\n\n /**\n * Create a new MJConversationEntity and automatically cache it\n * The cache is the ONLY place GetEntityObject() should be called\n * @param currentUser User context\n * @returns New MJConversationEntity instance (already cached)\n */\n async CreateConversation(currentUser: UserInfo): Promise<MJConversationEntity> {\n const md = this.Provider;\n const conversation = await md.GetEntityObject<MJConversationEntity>('MJ: Conversations', currentUser);\n\n // Automatically add to cache - user code doesn't need to do anything\n // Note: Conversation has no ID yet (not saved), so we can't deduplicate\n // After Save(), the ID will be populated and future getConversation() calls will find it\n this.conversations.push(conversation);\n\n return conversation;\n }\n\n /** @deprecated Use {@link CreateConversation}. */\n async createConversation(currentUser: UserInfo): Promise<MJConversationEntity> {\n return this.CreateConversation(currentUser);\n }\n\n /**\n * Remove a MJConversationEntity from the cache\n * @param id The conversation ID to remove\n */\n RemoveConversation(id: string): void {\n this.conversations = this.conversations.filter(c => !UUIDsEqual(c.ID, id));\n }\n\n /** @deprecated Use {@link RemoveConversation}. */\n removeConversation(id: string): void {\n return this.RemoveConversation(id);\n }\n\n /**\n * Get all cached MJConversationEntity objects (no DB call)\n * @returns Array of cached conversations\n */\n GetCachedConversations(): MJConversationEntity[] {\n return this.conversations;\n }\n\n /** @deprecated Use {@link GetCachedConversations}. */\n getCachedConversations(): MJConversationEntity[] {\n return this.GetCachedConversations();\n }\n\n // =============================================================================\n // MJConversationDetailEntity Methods\n // =============================================================================\n\n /**\n * Get a MJConversationDetailEntity by ID from cache, or load it if not cached\n * @param id The conversation detail ID\n * @param currentUser User context for loading\n * @returns The cached or loaded MJConversationDetailEntity, or null if not found\n */\n async GetConversationDetail(id: string, currentUser: UserInfo): Promise<MJConversationDetailEntity | null> {\n // Check cache first\n const cached = this.conversationDetails.find(d => UUIDsEqual(d.ID, id));\n if (cached) {\n return cached;\n }\n\n // Not in cache - load from DB\n const md = this.Provider;\n const detail = await md.GetEntityObject<MJConversationDetailEntity>('MJ: Conversation Details', currentUser);\n const loaded = await detail.Load(id);\n\n if (loaded) {\n // Add to cache\n this.conversationDetails.push(detail);\n return detail;\n }\n\n return null;\n }\n\n /** @deprecated Use {@link GetConversationDetail}. */\n async getConversationDetail(id: string, currentUser: UserInfo): Promise<MJConversationDetailEntity | null> {\n return this.GetConversationDetail(id, currentUser);\n }\n\n /**\n * Create a new MJConversationDetailEntity and automatically cache it\n * The cache is the ONLY place GetEntityObject() should be called\n * @param currentUser User context\n * @returns New MJConversationDetailEntity instance (already cached)\n */\n async CreateConversationDetail(currentUser: UserInfo): Promise<MJConversationDetailEntity> {\n const md = this.Provider;\n const detail = await md.GetEntityObject<MJConversationDetailEntity>('MJ: Conversation Details', currentUser);\n\n // Automatically add to cache - user code doesn't need to do anything\n // Note: Detail has no ID yet (not saved), so we can't deduplicate\n // After Save(), the ID will be populated and future getConversationDetail() calls will find it\n\n this.conversationDetails.push(detail);\n\n return detail;\n }\n\n /** @deprecated Use {@link CreateConversationDetail}. */\n async createConversationDetail(currentUser: UserInfo): Promise<MJConversationDetailEntity> {\n return this.CreateConversationDetail(currentUser);\n }\n\n /**\n * Load all ConversationDetail entities for a conversation and cache them\n * Used when loading a conversation's message history\n * @param conversationId The conversation ID\n * @param currentUser User context\n * @returns Array of MJConversationDetailEntity objects\n */\n async LoadConversationDetails(conversationId: string, currentUser: UserInfo): Promise<MJConversationDetailEntity[]> {\n const timestamp = new Date().toISOString();\n console.log(`[${timestamp}] 💾 DataCacheService.loadConversationDetails - Loading messages for conversation ${conversationId}`);\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n\n console.log(`[${timestamp}] 💾 DataCacheService - Executing RunView for Conversation Details`);\n const result = await rv.RunView<MJConversationDetailEntity>(\n {\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: `ConversationID='${conversationId}'`,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'entity_object'\n },\n currentUser\n );\n\n if (result.Success) {\n const details = result.Results || [];\n console.log(`[${timestamp}] 💾 DataCacheService - Loaded ${details.length} message(s) for conversation ${conversationId}`);\n\n // Add all to cache (avoid duplicates by checking ID)\n for (const detail of details) {\n const existingIndex = this.conversationDetails.findIndex(d => UUIDsEqual(d.ID, detail.ID));\n if (existingIndex >= 0) {\n // Replace existing (ensures we keep the same object reference)\n this.conversationDetails[existingIndex] = detail;\n } else {\n // Add new\n this.conversationDetails.push(detail);\n }\n }\n\n return details;\n }\n\n console.log(`[${timestamp}] 💾 DataCacheService - Failed to load messages for conversation ${conversationId}`);\n return [];\n }\n\n /** @deprecated Use {@link LoadConversationDetails}. */\n async loadConversationDetails(conversationId: string, currentUser: UserInfo): Promise<MJConversationDetailEntity[]> {\n return this.LoadConversationDetails(conversationId, currentUser);\n }\n\n /**\n * Get all cached ConversationDetail entities for a conversation (no DB call)\n * @param conversationId The conversation ID\n * @returns Array of cached conversation details\n */\n GetCachedConversationDetails(conversationId: string): MJConversationDetailEntity[] {\n return this.conversationDetails.filter(d => UUIDsEqual(d.ConversationID, conversationId));\n }\n\n /** @deprecated Use {@link GetCachedConversationDetails}. */\n getCachedConversationDetails(conversationId: string): MJConversationDetailEntity[] {\n return this.GetCachedConversationDetails(conversationId);\n }\n\n /**\n * Remove a MJConversationDetailEntity from the cache\n * @param id The conversation detail ID to remove\n */\n RemoveConversationDetail(id: string): void {\n this.conversationDetails = this.conversationDetails.filter(d => !UUIDsEqual(d.ID, id));\n }\n\n /** @deprecated Use {@link RemoveConversationDetail}. */\n removeConversationDetail(id: string): void {\n return this.RemoveConversationDetail(id);\n }\n\n // =============================================================================\n // Cache Management\n // =============================================================================\n\n /**\n * Refresh entity data by clearing cached entities of a specific type\n * This forces a reload from the database on next access\n * @param entityName The entity name to refresh (e.g., 'Conversations', 'MJ: Conversation Details')\n */\n async RefreshEntity(entityName: string): Promise<void> {\n switch (entityName) {\n case 'Conversations':\n this.conversations = [];\n break;\n case 'MJ: Conversation Details':\n this.conversationDetails = [];\n break;\n default:\n console.warn('Unknown entity name for refresh:', entityName);\n }\n }\n\n /** @deprecated Use {@link RefreshEntity}. */\n async refreshEntity(entityName: string): Promise<void> {\n return this.RefreshEntity(entityName);\n }\n\n /**\n * Refresh a specific cache by name\n * This method can be extended to handle different cache types\n * @param cacheName The cache name ('Core', 'AI', 'Actions')\n */\n async RefreshCache(cacheName: 'Core' | 'AI' | 'Actions'): Promise<void> {\n switch (cacheName) {\n case 'Core':\n // Clear core entity caches\n this.Clear();\n break;\n case 'AI':\n // AI-specific cache refresh would go here\n // For now, just log it\n console.log('AI cache refresh requested (not yet implemented)');\n break;\n case 'Actions':\n // Actions-specific cache refresh would go here\n console.log('Actions cache refresh requested (not yet implemented)');\n break;\n default:\n console.warn('Unknown cache name for refresh:', cacheName);\n }\n }\n\n /** @deprecated Use {@link RefreshCache}. */\n async refreshCache(cacheName: 'Core' | 'AI' | 'Actions'): Promise<void> {\n return this.RefreshCache(cacheName);\n }\n\n /**\n * Clear all cached entities\n * Call when switching environments, users, or when needed\n */\n Clear(): void {\n this.conversations = [];\n this.conversationDetails = [];\n }\n\n /** @deprecated Use {@link Clear}. */\n clear(): void {\n return this.Clear();\n }\n\n /**\n * Clear cached entities for a specific conversation\n * @param conversationId The conversation ID\n */\n ClearConversation(conversationId: string): void {\n this.conversations = this.conversations.filter(c => !UUIDsEqual(c.ID, conversationId));\n this.conversationDetails = this.conversationDetails.filter(d => !UUIDsEqual(d.ConversationID, conversationId));\n }\n\n /** @deprecated Use {@link ClearConversation}. */\n clearConversation(conversationId: string): void {\n return this.ClearConversation(conversationId);\n }\n\n /**\n * Get cache statistics for debugging\n * @returns Object with cache sizes\n */\n GetStats(): { conversations: number; conversationDetails: number } {\n return {\n conversations: this.conversations.length,\n conversationDetails: this.conversationDetails.length\n };\n }\n\n /** @deprecated Use {@link GetStats}. */\n getStats(): { conversations: number; conversationDetails: number } {\n return this.GetStats();\n }\n}\n"]}
1
+ {"version":3,"file":"data-cache.service.js","sourceRoot":"","sources":["../../../src/lib/services/data-cache.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { ConversationEngine, ConversationScope, MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';\nimport { Metadata, UserInfo, BaseEntity, RunView, IMetadataProvider } from '@memberjunction/core';\nimport { UUIDMap, UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Global singleton cache for conversation-related entities.\n * Maintains single instances of entities to prevent race conditions and ensure\n * all components see the same object state.\n *\n * Pattern: Instead of creating new entity instances with GetEntityObject() everywhere,\n * request entities from this cache. The cache returns the same instance each time,\n * so when one component updates entity.Status = 'Complete', all other components\n * see that change immediately without needing to reload from the database.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class DataCacheService {\n // Separate arrays for each entity type\n private conversations: MJConversationEntity[] = [];\n private conversationDetails: MJConversationDetailEntity[] = [];\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 // MJConversationEntity Methods\n // =============================================================================\n\n /**\n * Get a MJConversationEntity by ID from cache, or load it if not cached\n * @param id The conversation ID\n * @param currentUser User context for loading\n * @returns The cached or loaded MJConversationEntity, or null if not found\n */\n async GetConversation(id: string, currentUser: UserInfo): Promise<MJConversationEntity | null> {\n // Check cache first\n const cached = this.conversations.find(c => UUIDsEqual(c.ID, id));\n if (cached) {\n return cached;\n }\n\n // Not in cache - load from DB\n const md = this.Provider;\n const conversation = await md.GetEntityObject<MJConversationEntity>('MJ: Conversations', currentUser);\n const loaded = await conversation.Load(id);\n\n if (loaded) {\n // Add to cache\n this.conversations.push(conversation);\n return conversation;\n }\n\n return null;\n }\n\n /** @deprecated Use {@link GetConversation}. */\n async getConversation(id: string, currentUser: UserInfo): Promise<MJConversationEntity | null> {\n return this.GetConversation(id, currentUser);\n }\n\n /**\n * Create a new MJConversationEntity and automatically cache it\n * The cache is the ONLY place GetEntityObject() should be called\n * @param currentUser User context\n * @returns New MJConversationEntity instance (already cached)\n */\n async CreateConversation(currentUser: UserInfo): Promise<MJConversationEntity> {\n const md = this.Provider;\n const conversation = await md.GetEntityObject<MJConversationEntity>('MJ: Conversations', currentUser);\n\n // Automatically add to cache - user code doesn't need to do anything\n // Note: Conversation has no ID yet (not saved), so we can't deduplicate\n // After Save(), the ID will be populated and future getConversation() calls will find it\n this.conversations.push(conversation);\n\n return conversation;\n }\n\n /** @deprecated Use {@link CreateConversation}. */\n async createConversation(currentUser: UserInfo): Promise<MJConversationEntity> {\n return this.CreateConversation(currentUser);\n }\n\n /**\n * Remove a MJConversationEntity from the cache\n * @param id The conversation ID to remove\n */\n RemoveConversation(id: string): void {\n this.conversations = this.conversations.filter(c => !UUIDsEqual(c.ID, id));\n }\n\n /** @deprecated Use {@link RemoveConversation}. */\n removeConversation(id: string): void {\n return this.RemoveConversation(id);\n }\n\n /**\n * Get all cached MJConversationEntity objects (no DB call)\n * @returns Array of cached conversations\n */\n GetCachedConversations(): MJConversationEntity[] {\n return this.conversations;\n }\n\n /** @deprecated Use {@link GetCachedConversations}. */\n getCachedConversations(): MJConversationEntity[] {\n return this.GetCachedConversations();\n }\n\n // =============================================================================\n // MJConversationDetailEntity Methods\n // =============================================================================\n\n /**\n * Get a MJConversationDetailEntity by ID from cache, or load it if not cached\n * @param id The conversation detail ID\n * @param currentUser User context for loading\n * @returns The cached or loaded MJConversationDetailEntity, or null if not found\n */\n async GetConversationDetail(id: string, currentUser: UserInfo): Promise<MJConversationDetailEntity | null> {\n // Check cache first\n const cached = this.conversationDetails.find(d => UUIDsEqual(d.ID, id));\n if (cached) {\n return cached;\n }\n\n // Not in cache - load from DB\n const md = this.Provider;\n const detail = await md.GetEntityObject<MJConversationDetailEntity>('MJ: Conversation Details', currentUser);\n const loaded = await detail.Load(id);\n\n if (loaded) {\n // Add to cache\n this.conversationDetails.push(detail);\n return detail;\n }\n\n return null;\n }\n\n /** @deprecated Use {@link GetConversationDetail}. */\n async getConversationDetail(id: string, currentUser: UserInfo): Promise<MJConversationDetailEntity | null> {\n return this.GetConversationDetail(id, currentUser);\n }\n\n /**\n * Create a new MJConversationDetailEntity and automatically cache it\n * The cache is the ONLY place GetEntityObject() should be called\n * @param currentUser User context\n * @returns New MJConversationDetailEntity instance (already cached)\n */\n async CreateConversationDetail(currentUser: UserInfo): Promise<MJConversationDetailEntity> {\n const md = this.Provider;\n const detail = await md.GetEntityObject<MJConversationDetailEntity>('MJ: Conversation Details', currentUser);\n\n // Automatically add to cache - user code doesn't need to do anything\n // Note: Detail has no ID yet (not saved), so we can't deduplicate\n // After Save(), the ID will be populated and future getConversationDetail() calls will find it\n\n this.conversationDetails.push(detail);\n\n return detail;\n }\n\n /** @deprecated Use {@link CreateConversationDetail}. */\n async createConversationDetail(currentUser: UserInfo): Promise<MJConversationDetailEntity> {\n return this.CreateConversationDetail(currentUser);\n }\n\n /**\n * Load the ConversationDetail entities of one scope of a conversation (Main, or one fork's\n * path) that no rerun replaced, and cache them\n * @param conversationId The conversation ID\n * @param currentUser User context\n * @param scope The rows to read; Main when omitted\n * @returns Array of MJConversationDetailEntity objects\n * @throws when the scope belongs to another conversation\n */\n async LoadConversationDetails(conversationId: string, currentUser: UserInfo, scope?: ConversationScope): Promise<MJConversationDetailEntity[]> {\n if (scope && !UUIDsEqual(scope.ConversationID, conversationId)) {\n throw new Error(`Conversation ${conversationId} cannot be read with the scope of conversation ${scope.ConversationID}`);\n }\n const resolved = scope ?? ConversationEngine.TrunkScope(conversationId);\n const timestamp = new Date().toISOString();\n console.log(`[${timestamp}] 💾 DataCacheService.loadConversationDetails - Loading messages for conversation ${conversationId}`);\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n\n console.log(`[${timestamp}] 💾 DataCacheService - Executing RunView for Conversation Details`);\n const result = await rv.RunView<MJConversationDetailEntity>(\n {\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: ConversationEngine.LiveRowsFilter(ConversationEngine.ScopeFilter(resolved)),\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'entity_object'\n },\n currentUser\n );\n\n if (result.Success) {\n const details = result.Results || [];\n console.log(`[${timestamp}] 💾 DataCacheService - Loaded ${details.length} message(s) for conversation ${conversationId}`);\n\n this.upsertCachedDetails(details);\n return details;\n }\n\n console.log(`[${timestamp}] 💾 DataCacheService - Failed to load messages for conversation ${conversationId}`);\n return [];\n }\n\n /**\n * Adds loaded details to the cache, replacing any cached detail with the same ID in place.\n * Positions are indexed once up front: the cache spans every loaded conversation, so searching\n * it for each loaded detail grew with both.\n */\n private upsertCachedDetails(details: MJConversationDetailEntity[]): void {\n const positionByID = new UUIDMap<number>();\n this.conversationDetails.forEach((d, i) => {\n if (!positionByID.Has(d.ID)) positionByID.Set(d.ID, i);\n });\n for (const detail of details) {\n const existingIndex = positionByID.Get(detail.ID);\n if (existingIndex !== undefined) {\n // Replace existing (ensures we keep the same object reference)\n this.conversationDetails[existingIndex] = detail;\n } else {\n // Add new\n positionByID.Set(detail.ID, this.conversationDetails.length);\n this.conversationDetails.push(detail);\n }\n }\n }\n\n /** @deprecated Use {@link LoadConversationDetails}. */\n async loadConversationDetails(conversationId: string, currentUser: UserInfo, scope?: ConversationScope): Promise<MJConversationDetailEntity[]> {\n return this.LoadConversationDetails(conversationId, currentUser, scope);\n }\n\n /**\n * Get all cached ConversationDetail entities for a conversation (no DB call)\n * @param conversationId The conversation ID\n * @returns Array of cached conversation details\n */\n GetCachedConversationDetails(conversationId: string): MJConversationDetailEntity[] {\n return this.conversationDetails.filter(d => UUIDsEqual(d.ConversationID, conversationId));\n }\n\n /** @deprecated Use {@link GetCachedConversationDetails}. */\n getCachedConversationDetails(conversationId: string): MJConversationDetailEntity[] {\n return this.GetCachedConversationDetails(conversationId);\n }\n\n /**\n * Remove a MJConversationDetailEntity from the cache\n * @param id The conversation detail ID to remove\n */\n RemoveConversationDetail(id: string): void {\n this.conversationDetails = this.conversationDetails.filter(d => !UUIDsEqual(d.ID, id));\n }\n\n /** @deprecated Use {@link RemoveConversationDetail}. */\n removeConversationDetail(id: string): void {\n return this.RemoveConversationDetail(id);\n }\n\n // =============================================================================\n // Cache Management\n // =============================================================================\n\n /**\n * Refresh entity data by clearing cached entities of a specific type\n * This forces a reload from the database on next access\n * @param entityName The entity name to refresh (e.g., 'Conversations', 'MJ: Conversation Details')\n */\n async RefreshEntity(entityName: string): Promise<void> {\n switch (entityName) {\n case 'Conversations':\n this.conversations = [];\n break;\n case 'MJ: Conversation Details':\n this.conversationDetails = [];\n break;\n default:\n console.warn('Unknown entity name for refresh:', entityName);\n }\n }\n\n /** @deprecated Use {@link RefreshEntity}. */\n async refreshEntity(entityName: string): Promise<void> {\n return this.RefreshEntity(entityName);\n }\n\n /**\n * Refresh a specific cache by name\n * This method can be extended to handle different cache types\n * @param cacheName The cache name ('Core', 'AI', 'Actions')\n */\n async RefreshCache(cacheName: 'Core' | 'AI' | 'Actions'): Promise<void> {\n switch (cacheName) {\n case 'Core':\n // Clear core entity caches\n this.Clear();\n break;\n case 'AI':\n // AI-specific cache refresh would go here\n // For now, just log it\n console.log('AI cache refresh requested (not yet implemented)');\n break;\n case 'Actions':\n // Actions-specific cache refresh would go here\n console.log('Actions cache refresh requested (not yet implemented)');\n break;\n default:\n console.warn('Unknown cache name for refresh:', cacheName);\n }\n }\n\n /** @deprecated Use {@link RefreshCache}. */\n async refreshCache(cacheName: 'Core' | 'AI' | 'Actions'): Promise<void> {\n return this.RefreshCache(cacheName);\n }\n\n /**\n * Clear all cached entities\n * Call when switching environments, users, or when needed\n */\n Clear(): void {\n this.conversations = [];\n this.conversationDetails = [];\n }\n\n /** @deprecated Use {@link Clear}. */\n clear(): void {\n return this.Clear();\n }\n\n /**\n * Clear cached entities for a specific conversation\n * @param conversationId The conversation ID\n */\n ClearConversation(conversationId: string): void {\n this.conversations = this.conversations.filter(c => !UUIDsEqual(c.ID, conversationId));\n this.conversationDetails = this.conversationDetails.filter(d => !UUIDsEqual(d.ConversationID, conversationId));\n }\n\n /** @deprecated Use {@link ClearConversation}. */\n clearConversation(conversationId: string): void {\n return this.ClearConversation(conversationId);\n }\n\n /**\n * Get cache statistics for debugging\n * @returns Object with cache sizes\n */\n GetStats(): { conversations: number; conversationDetails: number } {\n return {\n conversations: this.conversations.length,\n conversationDetails: this.conversationDetails.length\n };\n }\n\n /** @deprecated Use {@link GetStats}. */\n getStats(): { conversations: number; conversationDetails: number } {\n return this.GetStats();\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';
1
+ import { ConversationScope, MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';
2
2
  import { UserInfo, IMetadataProvider } from '@memberjunction/core';
3
3
  import * as i0 from "@angular/core";
4
4
  export type ExportFormat = 'json' | 'markdown' | 'html' | 'text';
@@ -88,6 +88,16 @@ export interface ExportOptions {
88
88
  * map via {@link ExportBranding.brandTokens} instead.
89
89
  */
90
90
  export declare const DEFAULT_EXPORT_THEME_TOKENS: readonly string[];
91
+ /** The conversation and the messages one export writes. */
92
+ export interface ExportConversationData {
93
+ conversation: MJConversationEntity;
94
+ details: MJConversationDetailEntity[];
95
+ /**
96
+ * The fork the messages come from, as the header names it (its display name). Absent or null
97
+ * in Main.
98
+ */
99
+ fork?: string | null;
100
+ }
91
101
  export declare class ExportService {
92
102
  private _provider;
93
103
  /**
@@ -95,19 +105,23 @@ export declare class ExportService {
95
105
  */
96
106
  set Provider(value: IMetadataProvider | null);
97
107
  get Provider(): IMetadataProvider;
98
- ExportConversation(conversationId: string, format: ExportFormat, currentUser: UserInfo, options?: ExportOptions): Promise<void>;
99
- /** @deprecated Use {@link ExportConversation}. */
100
- exportConversation(conversationId: string, format: ExportFormat, currentUser: UserInfo, options?: ExportOptions): Promise<void>;
108
+ /**
109
+ * Exports the messages of one scope of a conversation (Main, or one fork's path) and
110
+ * downloads the file. In a fork the export header names the fork.
111
+ * @throws when the scope belongs to another conversation, or the conversation is not found.
112
+ */
113
+ ExportConversation(conversationId: string, scope: ConversationScope, format: ExportFormat, currentUser: UserInfo, options?: ExportOptions): Promise<void>;
114
+ /**
115
+ * @deprecated Use {@link ExportConversation}. Without `scope`, exports Main.
116
+ */
117
+ exportConversation(conversationId: string, format: ExportFormat, currentUser: UserInfo, options?: ExportOptions, scope?: ConversationScope): Promise<void>;
101
118
  /**
102
119
  * Build the export document for already-loaded conversation data — the
103
- * download-free seam of {@link exportConversation}. Async because HTML-format
120
+ * download-free seam of {@link ExportConversation}. Async because HTML-format
104
121
  * branding may inline a logo. Exposed publicly so hosts (and tests) can build
105
122
  * export content without triggering a browser download.
106
123
  */
107
- BuildExportContent(data: {
108
- conversation: MJConversationEntity;
109
- details: MJConversationDetailEntity[];
110
- }, format: ExportFormat, options?: ExportOptions): Promise<{
124
+ BuildExportContent(data: ExportConversationData, format: ExportFormat, options?: ExportOptions): Promise<{
111
125
  content: string;
112
126
  filename: string;
113
127
  mimeType: string;
@@ -164,7 +178,10 @@ export declare class ExportService {
164
178
  * (or when the response isn't actually an image — don't inline HTML/other as
165
179
  * a bogus `data:` image). */
166
180
  private inlineLogo;
181
+ /** Loads the conversation and the messages in the scope that no rerun replaced, in Sequence order. */
167
182
  private loadConversationData;
183
+ /** The header name of the scope's fork: its display name; null in Main. */
184
+ private forkLabel;
168
185
  private exportAsJSON;
169
186
  private exportAsMarkdown;
170
187
  private exportAsHTML;
@@ -1 +1 @@
1
- {"version":3,"file":"export.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/export.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"export.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/export.service.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  import { Injectable } from '@angular/core';
2
+ import { ConversationEngine } from '@memberjunction/core-entities';
2
3
  import { RunView, Metadata } from '@memberjunction/core';
4
+ import { UUIDsEqual } from '@memberjunction/global';
3
5
  import * as i0 from "@angular/core";
4
6
  /**
5
7
  * Tokens captured by the theme auto-snapshot — exactly the custom properties the
@@ -29,18 +31,26 @@ export class ExportService {
29
31
  get Provider() {
30
32
  return this._provider ?? Metadata.Provider;
31
33
  }
32
- async ExportConversation(conversationId, format, currentUser, options = {}) {
33
- const conversation = await this.loadConversationData(conversationId, currentUser);
34
+ /**
35
+ * Exports the messages of one scope of a conversation (Main, or one fork's path) and
36
+ * downloads the file. In a fork the export header names the fork.
37
+ * @throws when the scope belongs to another conversation, or the conversation is not found.
38
+ */
39
+ async ExportConversation(conversationId, scope, format, currentUser, options = {}) {
40
+ const conversation = await this.loadConversationData(conversationId, scope, currentUser);
34
41
  const { content, filename, mimeType } = await this.BuildExportContent(conversation, format, options);
35
42
  this.downloadFile(content, filename, mimeType);
36
43
  }
37
- /** @deprecated Use {@link ExportConversation}. */
38
- async exportConversation(conversationId, format, currentUser, options = {}) {
39
- return this.ExportConversation(conversationId, format, currentUser, options);
44
+ /**
45
+ * @deprecated Use {@link ExportConversation}. Without `scope`, exports Main.
46
+ */
47
+ async exportConversation(conversationId, format, currentUser, options = {}, scope) {
48
+ const resolved = scope ?? ConversationEngine.TrunkScope(conversationId);
49
+ return this.ExportConversation(conversationId, resolved, format, currentUser, options);
40
50
  }
41
51
  /**
42
52
  * Build the export document for already-loaded conversation data — the
43
- * download-free seam of {@link exportConversation}. Async because HTML-format
53
+ * download-free seam of {@link ExportConversation}. Async because HTML-format
44
54
  * branding may inline a logo. Exposed publicly so hosts (and tests) can build
45
55
  * export content without triggering a browser download.
46
56
  */
@@ -249,7 +259,11 @@ export class ExportService {
249
259
  return url;
250
260
  }
251
261
  }
252
- async loadConversationData(conversationId, currentUser) {
262
+ /** Loads the conversation and the messages in the scope that no rerun replaced, in Sequence order. */
263
+ async loadConversationData(conversationId, scope, currentUser) {
264
+ if (!UUIDsEqual(scope.ConversationID, conversationId)) {
265
+ throw new Error(`Conversation ${conversationId} cannot be exported with the scope of conversation ${scope.ConversationID}`);
266
+ }
253
267
  const rv = RunView.FromMetadataProvider(this.Provider);
254
268
  // Load conversation and details in parallel
255
269
  const [conversationResult, detailsResult] = await rv.RunViews([
@@ -260,7 +274,7 @@ export class ExportService {
260
274
  },
261
275
  {
262
276
  EntityName: 'MJ: Conversation Details',
263
- ExtraFilter: `ConversationID='${conversationId}'`,
277
+ ExtraFilter: ConversationEngine.LiveRowsFilter(ConversationEngine.ScopeFilter(scope)),
264
278
  OrderBy: 'Sequence ASC',
265
279
  ResultType: 'entity_object'
266
280
  }
@@ -268,28 +282,44 @@ export class ExportService {
268
282
  if (!conversationResult.Success || !conversationResult.Results?.length) {
269
283
  throw new Error('Conversation not found');
270
284
  }
285
+ const details = (detailsResult.Results || []);
271
286
  return {
272
287
  conversation: conversationResult.Results[0],
273
- details: (detailsResult.Results || [])
288
+ details,
289
+ fork: this.forkLabel(scope, details)
274
290
  };
275
291
  }
292
+ /** The header name of the scope's fork: its display name; null in Main. */
293
+ forkLabel(scope, details) {
294
+ if (scope.BranchID == null) {
295
+ return null;
296
+ }
297
+ const fork = scope.Branches.find(b => UUIDsEqual(b.ID, scope.BranchID));
298
+ if (!fork) {
299
+ return scope.BranchID;
300
+ }
301
+ const first = [...details]
302
+ .filter(d => UUIDsEqual(d.BranchID ?? null, scope.BranchID))
303
+ .sort((a, b) => a.Sequence - b.Sequence)
304
+ .find(d => ConversationEngine.ForkPlainText(d.Message) != null);
305
+ return ConversationEngine.ForkDisplayName(fork, first?.Message ?? null);
306
+ }
276
307
  exportAsJSON(data, options) {
277
308
  const exportData = {};
278
309
  // Add metadata if requested
279
- if (options.includeMetadata) {
280
- exportData.conversation = {
310
+ const conversationBlock = options.includeMetadata
311
+ ? {
281
312
  id: data.conversation.ID,
282
313
  name: data.conversation.Name,
283
314
  description: data.conversation.Description,
284
315
  createdAt: data.conversation.__mj_CreatedAt,
285
316
  updatedAt: data.conversation.__mj_UpdatedAt
286
- };
287
- }
288
- else {
289
- exportData.conversation = {
290
- name: data.conversation.Name
291
- };
317
+ }
318
+ : { name: data.conversation.Name };
319
+ if (data.fork) {
320
+ conversationBlock.fork = data.fork;
292
321
  }
322
+ exportData.conversation = conversationBlock;
293
323
  // Branding block (title / trademark / logo) when the host supplied branding —
294
324
  // the data-format analogue of the HTML header + trademark footer.
295
325
  const branding = this.buildBrandingBlock(options);
@@ -331,6 +361,9 @@ export class ExportService {
331
361
  if (options.includeMetadata) {
332
362
  md += `**Created:** ${this.formatDate(data.conversation.__mj_CreatedAt)}\n\n`;
333
363
  }
364
+ if (data.fork) {
365
+ md += `**Fork:** ${data.fork}\n\n`;
366
+ }
334
367
  md += `---\n\n`;
335
368
  if (options.includeMessages) {
336
369
  for (const detail of data.details) {
@@ -378,11 +411,18 @@ export class ExportService {
378
411
  <body>
379
412
  ${theme.logoDataUri ? `<img class="brand-logo" src="${this.escapeAttr(theme.logoDataUri)}" alt="" />
380
413
  ` : ''}<h1>${this.escapeHtml(title)}</h1>`;
414
+ const forkLine = data.fork ? `
415
+ <p>Fork: ${this.escapeHtml(data.fork)}</p>` : '';
381
416
  if (options.includeMetadata) {
382
417
  html += `
383
418
  <div class="meta">
384
419
  ${data.conversation.Description ? `<p>${this.escapeHtml(data.conversation.Description)}</p>` : ''}
385
- <p>Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}</p>
420
+ <p>Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}</p>${forkLine}
421
+ </div>`;
422
+ }
423
+ else if (forkLine) {
424
+ html += `
425
+ <div class="meta">${forkLine}
386
426
  </div>`;
387
427
  }
388
428
  if (options.includeMessages) {
@@ -419,6 +459,9 @@ export class ExportService {
419
459
  if (options.includeMetadata) {
420
460
  text += `Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}\n\n`;
421
461
  }
462
+ if (data.fork) {
463
+ text += `Fork: ${data.fork}\n\n`;
464
+ }
422
465
  text += '-'.repeat(80) + '\n\n';
423
466
  if (options.includeMessages) {
424
467
  for (const detail of data.details) {