@flamingo-stack/openframe-frontend-core 0.0.468-snapshot.20260723140929 → 0.0.468

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 (280) hide show
  1. package/dist/{chunk-TOFOK7G5.cjs → chunk-2WZAR2MB.cjs} +37 -37
  2. package/dist/{chunk-TOFOK7G5.cjs.map → chunk-2WZAR2MB.cjs.map} +1 -1
  3. package/dist/{chunk-YXNWEVER.cjs → chunk-3I34MUEG.cjs} +62 -62
  4. package/dist/{chunk-YXNWEVER.cjs.map → chunk-3I34MUEG.cjs.map} +1 -1
  5. package/dist/{chunk-4W54HUP7.cjs → chunk-3PLQWO4H.cjs} +4896 -7014
  6. package/dist/chunk-3PLQWO4H.cjs.map +1 -0
  7. package/dist/{chunk-33FDAZDB.js → chunk-3TU6QURP.js} +2 -2
  8. package/dist/{chunk-2BJSRTKU.js → chunk-AEM7ADDG.js} +2 -2
  9. package/dist/{chunk-VUCYS36H.js → chunk-CLW2S55N.js} +10 -10
  10. package/dist/chunk-CLW2S55N.js.map +1 -0
  11. package/dist/{chunk-LRESZO4L.cjs → chunk-ELIY4AO2.cjs} +26 -26
  12. package/dist/{chunk-LRESZO4L.cjs.map → chunk-ELIY4AO2.cjs.map} +1 -1
  13. package/dist/{chunk-MMF6HJB7.js → chunk-EZESVVIM.js} +4 -4
  14. package/dist/{chunk-AW3LVWVV.js → chunk-HTSWLPMU.js} +2 -2
  15. package/dist/{chunk-MTLBBSLP.cjs → chunk-HVLMAT4T.cjs} +5 -5
  16. package/dist/{chunk-MTLBBSLP.cjs.map → chunk-HVLMAT4T.cjs.map} +1 -1
  17. package/dist/{chunk-RPAOSHBN.js → chunk-IUMPVRSH.js} +2 -2
  18. package/dist/{chunk-5HUTT3FD.cjs → chunk-J6CE6HZS.cjs} +11 -11
  19. package/dist/{chunk-5HUTT3FD.cjs.map → chunk-J6CE6HZS.cjs.map} +1 -1
  20. package/dist/{chunk-7I2QMUEZ.js → chunk-JW3UNHGW.js} +2 -2
  21. package/dist/{chunk-4UFRQT7Z.cjs → chunk-L3BWGFHT.cjs} +15 -15
  22. package/dist/{chunk-4UFRQT7Z.cjs.map → chunk-L3BWGFHT.cjs.map} +1 -1
  23. package/dist/{chunk-WHWDGCQV.cjs → chunk-MULVIGIN.cjs} +60 -60
  24. package/dist/chunk-MULVIGIN.cjs.map +1 -0
  25. package/dist/{chunk-AJSNF5YF.js → chunk-O2QOC5FA.js} +5 -6
  26. package/dist/chunk-O2QOC5FA.js.map +1 -0
  27. package/dist/{chunk-E6O6XATC.js → chunk-P5SLNM3C.js} +9699 -11817
  28. package/dist/chunk-P5SLNM3C.js.map +1 -0
  29. package/dist/{chunk-GYEZV4GK.js → chunk-QTGYQ2U7.js} +2 -2
  30. package/dist/{chunk-4QDFNDVW.js → chunk-QZJN5OHK.js} +4 -4
  31. package/dist/{chunk-U2KPMWO6.cjs → chunk-TISXEAGH.cjs} +7 -7
  32. package/dist/{chunk-U2KPMWO6.cjs.map → chunk-TISXEAGH.cjs.map} +1 -1
  33. package/dist/{chunk-V5YWOQBP.cjs → chunk-VHFH3BG6.cjs} +31 -31
  34. package/dist/{chunk-V5YWOQBP.cjs.map → chunk-VHFH3BG6.cjs.map} +1 -1
  35. package/dist/{chunk-OVIUQJ2H.cjs → chunk-VRJXY6TM.cjs} +27 -28
  36. package/dist/chunk-VRJXY6TM.cjs.map +1 -0
  37. package/dist/{chunk-DG7TX763.js → chunk-VYUEOKI6.js} +2 -2
  38. package/dist/{chunk-GLKULDQN.cjs → chunk-X77X3RKH.cjs} +9 -9
  39. package/dist/{chunk-GLKULDQN.cjs.map → chunk-X77X3RKH.cjs.map} +1 -1
  40. package/dist/components/case-studies/index.cjs +8 -8
  41. package/dist/components/case-studies/index.js +2 -2
  42. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  43. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  44. package/dist/components/chat/hooks/index.d.ts +1 -0
  45. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  46. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  47. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +48 -15
  48. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  49. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +6 -0
  50. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -0
  51. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +47 -3
  52. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  53. package/dist/components/chat/index.cjs +2 -10
  54. package/dist/components/chat/index.cjs.map +1 -1
  55. package/dist/components/chat/index.d.ts +0 -1
  56. package/dist/components/chat/index.d.ts.map +1 -1
  57. package/dist/components/chat/index.js +13 -21
  58. package/dist/components/chat/types/api.types.d.ts +81 -1
  59. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  60. package/dist/components/chat/types/processing.types.d.ts +90 -2
  61. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  62. package/dist/components/chat/utils/chunk-parser.d.ts +25 -0
  63. package/dist/components/chat/utils/chunk-parser.d.ts.map +1 -0
  64. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +6 -34
  65. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  66. package/dist/components/chat/utils/index.d.ts +3 -2
  67. package/dist/components/chat/utils/index.d.ts.map +1 -1
  68. package/dist/components/chat/utils/process-historical-messages.d.ts +11 -59
  69. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  70. package/dist/components/contact/index.cjs +3 -3
  71. package/dist/components/contact/index.js +2 -2
  72. package/dist/components/docs/index.cjs +5 -5
  73. package/dist/components/docs/index.js +4 -4
  74. package/dist/components/embeds/index.cjs +3 -3
  75. package/dist/components/embeds/index.js +2 -2
  76. package/dist/components/faq/index.cjs +3 -3
  77. package/dist/components/faq/index.js +2 -2
  78. package/dist/components/features/index.cjs +2 -2
  79. package/dist/components/features/index.js +1 -1
  80. package/dist/components/help-center-pages/index.cjs +20 -20
  81. package/dist/components/help-center-pages/index.js +11 -11
  82. package/dist/components/index.cjs +130 -172
  83. package/dist/components/index.cjs.map +1 -1
  84. package/dist/components/index.js +21 -63
  85. package/dist/components/index.js.map +1 -1
  86. package/dist/components/navigation/index.cjs +2 -2
  87. package/dist/components/navigation/index.js +1 -1
  88. package/dist/components/onboarding-guides/index.cjs +5 -5
  89. package/dist/components/onboarding-guides/index.js +4 -4
  90. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  91. package/dist/components/related-content/index.cjs +3 -3
  92. package/dist/components/related-content/index.js +2 -2
  93. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  94. package/dist/components/tickets/index.cjs +5 -5
  95. package/dist/components/tickets/index.js +4 -4
  96. package/dist/components/ui/index.cjs +2 -44
  97. package/dist/components/ui/index.cjs.map +1 -1
  98. package/dist/components/ui/index.d.ts +2 -1
  99. package/dist/components/ui/index.d.ts.map +1 -1
  100. package/dist/components/ui/index.js +13 -55
  101. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  102. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  103. package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
  104. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
  105. package/dist/index.cjs +2 -60
  106. package/dist/index.cjs.map +1 -1
  107. package/dist/index.js +13 -71
  108. package/dist/utils/index.cjs +40 -169
  109. package/dist/utils/index.cjs.map +1 -1
  110. package/dist/utils/index.d.ts +0 -1
  111. package/dist/utils/index.d.ts.map +1 -1
  112. package/dist/utils/index.js +41 -162
  113. package/dist/utils/index.js.map +1 -1
  114. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  115. package/package.json +1 -7
  116. package/src/components/chat/__tests__/chat-message-list.test.tsx +5 -293
  117. package/src/components/chat/chat-message-enhanced.tsx +17 -111
  118. package/src/components/chat/chat-message-list.tsx +109 -358
  119. package/src/components/chat/embeddable-chat.tsx +0 -6
  120. package/src/components/chat/hooks/.index.md +1 -1
  121. package/src/components/chat/hooks/.use-nats-chat-adapter.md +1 -1
  122. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +50 -0
  123. package/src/components/chat/hooks/index.ts +1 -0
  124. package/src/components/chat/hooks/use-chat.ts +0 -8
  125. package/src/components/chat/hooks/use-nats-chat-adapter.ts +822 -243
  126. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +479 -0
  127. package/src/components/chat/hooks/use-sse-chat-adapter.ts +666 -318
  128. package/src/components/chat/index.ts +0 -5
  129. package/src/components/chat/thinking-display.tsx +1 -1
  130. package/src/components/chat/types/.api.types.md +3 -1
  131. package/src/components/chat/types/.processing.types.md +23 -6
  132. package/src/components/chat/types/api.types.ts +73 -6
  133. package/src/components/chat/types/processing.types.ts +52 -11
  134. package/src/components/chat/utils/.chunk-parser.md +51 -0
  135. package/src/components/chat/utils/.index.md +5 -0
  136. package/src/components/chat/utils/chunk-parser.ts +255 -0
  137. package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
  138. package/src/components/chat/utils/index.ts +8 -5
  139. package/src/components/chat/utils/process-historical-messages.ts +383 -352
  140. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
  141. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  142. package/src/components/shared/product-release/release-detail-page.tsx +4 -19
  143. package/src/components/ui/.simple-markdown-renderer.md +40 -0
  144. package/src/components/ui/index.ts +2 -1
  145. package/src/components/ui/release-changelog-section.tsx +1 -1
  146. package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
  147. package/src/components/ui/simple-markdown-renderer.tsx +965 -0
  148. package/src/components/ui/ticket-info-section.tsx +1 -1
  149. package/src/utils/index.ts +0 -1
  150. package/src/utils/markdown-section-extractor.ts +56 -41
  151. package/dist/chat-protocol/decode.d.ts +0 -58
  152. package/dist/chat-protocol/decode.d.ts.map +0 -1
  153. package/dist/chat-protocol/encode.d.ts +0 -44
  154. package/dist/chat-protocol/encode.d.ts.map +0 -1
  155. package/dist/chat-protocol/env-flag.d.ts +0 -35
  156. package/dist/chat-protocol/env-flag.d.ts.map +0 -1
  157. package/dist/chat-protocol/events.d.ts +0 -192
  158. package/dist/chat-protocol/events.d.ts.map +0 -1
  159. package/dist/chat-protocol/frames.d.ts +0 -206
  160. package/dist/chat-protocol/frames.d.ts.map +0 -1
  161. package/dist/chat-protocol/index.cjs +0 -493
  162. package/dist/chat-protocol/index.cjs.map +0 -1
  163. package/dist/chat-protocol/index.d.ts +0 -18
  164. package/dist/chat-protocol/index.d.ts.map +0 -1
  165. package/dist/chat-protocol/index.js +0 -477
  166. package/dist/chat-protocol/index.js.map +0 -1
  167. package/dist/chat-protocol/ip-normalize.d.ts +0 -44
  168. package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
  169. package/dist/chat-protocol/nats-decoder.d.ts +0 -26
  170. package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
  171. package/dist/chunk-4W54HUP7.cjs.map +0 -1
  172. package/dist/chunk-AJSNF5YF.js.map +0 -1
  173. package/dist/chunk-E6O6XATC.js.map +0 -1
  174. package/dist/chunk-OVIUQJ2H.cjs.map +0 -1
  175. package/dist/chunk-VUCYS36H.js.map +0 -1
  176. package/dist/chunk-WHWDGCQV.cjs.map +0 -1
  177. package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
  178. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
  179. package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
  180. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
  181. package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
  182. package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
  183. package/dist/components/chat/stream/index.d.ts +0 -17
  184. package/dist/components/chat/stream/index.d.ts.map +0 -1
  185. package/dist/components/chat/stream/message-mutations.d.ts +0 -77
  186. package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
  187. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
  188. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
  189. package/dist/components/ui/markdown/base-components.d.ts +0 -56
  190. package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
  191. package/dist/components/ui/markdown/engine.d.ts +0 -99
  192. package/dist/components/ui/markdown/engine.d.ts.map +0 -1
  193. package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
  194. package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
  195. package/dist/components/ui/markdown/index.d.ts +0 -18
  196. package/dist/components/ui/markdown/index.d.ts.map +0 -1
  197. package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
  198. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
  199. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
  200. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
  201. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
  202. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
  203. package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
  204. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
  205. package/dist/components/ui/markdown/sanitize.d.ts +0 -153
  206. package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
  207. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
  208. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
  209. package/dist/components/ui/markdown/streaming.d.ts +0 -78
  210. package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
  211. package/dist/components/ui/markdown/text-size.d.ts +0 -34
  212. package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
  213. package/dist/utils/markdown-fences.d.ts +0 -42
  214. package/dist/utils/markdown-fences.d.ts.map +0 -1
  215. package/dist/utils/markdown-heading-id.d.ts +0 -85
  216. package/dist/utils/markdown-heading-id.d.ts.map +0 -1
  217. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -307
  218. package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -515
  219. package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
  220. package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
  221. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -228
  222. package/src/chat-protocol/decode.ts +0 -277
  223. package/src/chat-protocol/encode.ts +0 -71
  224. package/src/chat-protocol/env-flag.ts +0 -39
  225. package/src/chat-protocol/events.ts +0 -228
  226. package/src/chat-protocol/frames.ts +0 -238
  227. package/src/chat-protocol/index.ts +0 -21
  228. package/src/chat-protocol/ip-normalize.ts +0 -146
  229. package/src/chat-protocol/nats-decoder.ts +0 -252
  230. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
  231. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -209
  232. package/src/components/chat/hooks/__tests__/__snapshots__/persisted-state-v1-golden.test.ts.snap +0 -297
  233. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  234. package/src/components/chat/hooks/__tests__/persisted-state-v1-golden.test.ts +0 -272
  235. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
  236. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -937
  237. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -756
  238. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -460
  239. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -894
  240. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
  241. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -98
  242. package/src/components/chat/stream/chat-dialog-store.ts +0 -536
  243. package/src/components/chat/stream/chat-stream-reducer.ts +0 -1796
  244. package/src/components/chat/stream/delta-batcher.ts +0 -159
  245. package/src/components/chat/stream/index.ts +0 -55
  246. package/src/components/chat/stream/message-mutations.ts +0 -338
  247. package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
  248. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -418
  249. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -599
  250. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -317
  251. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
  252. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
  253. package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2528
  254. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -115
  255. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -95
  256. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -309
  257. package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -388
  258. package/src/components/ui/markdown/base-components.tsx +0 -341
  259. package/src/components/ui/markdown/engine.tsx +0 -315
  260. package/src/components/ui/markdown/heading-ids.ts +0 -239
  261. package/src/components/ui/markdown/index.ts +0 -49
  262. package/src/components/ui/markdown/mermaid-diagram.tsx +0 -291
  263. package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
  264. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
  265. package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
  266. package/src/components/ui/markdown/sanitize.ts +0 -3499
  267. package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
  268. package/src/components/ui/markdown/streaming.ts +0 -362
  269. package/src/components/ui/markdown/text-size.ts +0 -106
  270. package/src/utils/markdown-fences.ts +0 -127
  271. package/src/utils/markdown-heading-id.ts +0 -348
  272. /package/dist/{chunk-33FDAZDB.js.map → chunk-3TU6QURP.js.map} +0 -0
  273. /package/dist/{chunk-2BJSRTKU.js.map → chunk-AEM7ADDG.js.map} +0 -0
  274. /package/dist/{chunk-MMF6HJB7.js.map → chunk-EZESVVIM.js.map} +0 -0
  275. /package/dist/{chunk-AW3LVWVV.js.map → chunk-HTSWLPMU.js.map} +0 -0
  276. /package/dist/{chunk-RPAOSHBN.js.map → chunk-IUMPVRSH.js.map} +0 -0
  277. /package/dist/{chunk-7I2QMUEZ.js.map → chunk-JW3UNHGW.js.map} +0 -0
  278. /package/dist/{chunk-GYEZV4GK.js.map → chunk-QTGYQ2U7.js.map} +0 -0
  279. /package/dist/{chunk-4QDFNDVW.js.map → chunk-QZJN5OHK.js.map} +0 -0
  280. /package/dist/{chunk-DG7TX763.js.map → chunk-VYUEOKI6.js.map} +0 -0
@@ -15,7 +15,7 @@
15
15
  * renderer with extra plugins.
16
16
  */
17
17
 
18
- import { Fragment, type ComponentType, type ReactNode } from 'react'
18
+ import { type ComponentType, type ReactNode } from 'react'
19
19
  import { PageLayout } from '../layout/page-layout'
20
20
 
21
21
  import { useRouter } from '../../embed-shims'
@@ -30,7 +30,7 @@ import { VideoBitesStrip } from '../features/video-bites-strip'
30
30
  import { toStripProfile } from '../features/video-bites-shared'
31
31
  import { useVideoWarmup } from '../features/use-video-warmup'
32
32
  import { getCaptionsUrl } from '../features/captions-url'
33
- import { RichMarkdownRenderer } from '../ui/markdown'
33
+ import { RichMarkdownRenderer } from '../ui/rich-markdown-renderer'
34
34
  import { EntityTagBadges } from '../features/entity-tag-badges'
35
35
  import { LoadError } from '../ui/error-state'
36
36
  import { ArticleAuthorByline } from '../shared/article-author-byline'
@@ -244,26 +244,8 @@ export function OnboardingGuideDetailView({
244
244
  </div>
245
245
  )}
246
246
 
247
- {/*
248
- * Host slot — cross-type related-content / FAQ rail.
249
- *
250
- * KEYED DELIBERATELY. This is one member of PageLayout's static children
251
- * array, and the only member whose element may be created in a SERVER
252
- * component and crossed over the RSC boundary. Static JSX children are
253
- * normally exempt from the key warning because `jsxs` runs
254
- * `validateChildKeys` and stamps `_store.validated = 1` on each element —
255
- * but a slot arriving over the wire is referenced as a lazy chunk wrapper,
256
- * so validation marks the WRAPPER and the fulfilled path never copies the
257
- * flag onto the revived element. It reaches the reconciler with
258
- * `validated: 0, key: null` and warns, blaming PageLayout (the owner of the
259
- * enclosing element) rather than anything actually at fault.
260
- *
261
- * A keyed Fragment emits no DOM, so rendered output is byte-identical.
262
- * Do NOT "fix" this in PageLayout via `React.Children.toArray` — that would
263
- * auto-key every consumer's children and change reconciliation identity for
264
- * all of them, and that file carries an explicit FROZEN contract.
265
- */}
266
- <Fragment key="related-content">{relatedContent}</Fragment>
247
+ {/* Host slot — cross-type related-content / FAQ rail. */}
248
+ {relatedContent}
267
249
  </PageLayout>
268
250
  )
269
251
  }
@@ -19,7 +19,7 @@
19
19
 
20
20
  import type { ComponentType } from 'react';
21
21
  import { PageShell, PageLayout } from '../../ui';
22
- import { RichMarkdownRenderer } from '../../ui/markdown';
22
+ import { RichMarkdownRenderer } from '../../ui/rich-markdown-renderer';
23
23
  import { useRouter } from '../../../embed-shims/next-navigation';
24
24
  import { useLegalDocs, type LegalDocument } from './use-legal-docs';
25
25
  import { formatLegalDate } from '../../../utils/format';
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useState, useEffect, Fragment, ComponentType, type ReactNode } from 'react';
3
+ import { useState, useEffect, ComponentType, type ReactNode } from 'react';
4
4
  import Link from '../../../embed-shims/next-link';
5
5
  import { useRouter } from '../../../embed-shims/next-navigation';
6
6
  import { Card, CardContent } from '../../ui/card';
@@ -11,7 +11,7 @@ import { PageShell } from '../../layout/article-detail-layout';
11
11
  import { PageLayout } from '../../layout/page-layout';
12
12
  import { FadePreview } from '../../ui/fade-preview';
13
13
  import { ReleaseChangelogSection } from '../../ui/release-changelog-section';
14
- import { RichMarkdownRenderer } from '../../ui/markdown';
14
+ import { RichMarkdownRenderer } from '../../ui/rich-markdown-renderer';
15
15
  import { EntityTagBadges } from '../../features/entity-tag-badges';
16
16
  import { EntityMetadataAuthorCell } from '../../chat/entity-cards/entity-author-card';
17
17
  import type { EntityAuthor } from '../../../types/entity-author';
@@ -582,23 +582,8 @@ export function ReleaseDetailPage({
582
582
  )}
583
583
  </div>
584
584
 
585
- {/*
586
- * Host slot — end-of-article byline + related-content / FAQ rail.
587
- *
588
- * KEYED for the same reason as `onboarding-guide-detail-view.tsx`: this is a
589
- * member of PageLayout's static children array, and a slot element built in a
590
- * SERVER component crosses the RSC boundary as a lazy chunk wrapper, so
591
- * `validateChildKeys` marks the wrapper and the fulfilled path never copies
592
- * `_store.validated` onto the revived element — it reaches the reconciler
593
- * unvalidated and warns.
594
- *
595
- * Today the hub's only consumer of this view is a `'use client'` wrapper that
596
- * builds the slot locally, so no element actually crosses the boundary and
597
- * this is pre-emptive. It is kept because the trap is invisible from here: a
598
- * future server-built slot would warn with no clue pointing at this line.
599
- * A keyed Fragment emits no DOM, so output is byte-identical either way.
600
- */}
601
- <Fragment key="related-content">{relatedContent}</Fragment>
585
+ {/* Host slot — end-of-article byline + related-content / FAQ rail. */}
586
+ {relatedContent}
602
587
  </PageLayout>
603
588
  );
604
589
  }
@@ -0,0 +1,40 @@
1
+ <!-- source-hash: cb258dc120396ef8c715487b0cdc1022 -->
2
+ Client-side React component that renders LLM-generated markdown safely, combining `react-markdown` with a custom XSS sanitization pipeline and support for GitHub-flavored markdown, syntax highlighting, and embedded media.
3
+
4
+ ## Key Components
5
+
6
+ ### Security Pipeline
7
+ - **`rehypeStripUnsafe()`** — Custom rehype plugin that strips dangerous HAST nodes after `rehype-raw` parsing. Removes `<script>`, `<style>`, `<object>`, event handler attributes (`on*`), `javascript:` / `data:` URIs, and `iframe srcdoc` vectors.
8
+ - **`srcsetHasUnsafeCandidate()`** — Inspects every candidate URL in `srcset` attributes (not just the first), preventing multi-candidate injection attacks.
9
+ - **`escapeUnknownHtmlTags()`** — Pre-processes markdown text to escape HTML tags not in the `SAFE_HTML_TAGS` allowlist, preventing LLM-emitted XML-style tags (e.g., `<ticket>`, `<their>`) from reaching React as unrecognized custom elements. Preserves code blocks and inline code spans.
10
+ - **`cardAwareUrlTransform()`** — Extends `react-markdown`'s default URL sanitizer to allow the internal `card://` scheme for chat-card markers while keeping all other unsafe schemes blocked.
11
+
12
+ ### Constants & Regexes
13
+ | Export | Purpose |
14
+ |--------|---------|
15
+ | `SAFE_HTML_TAGS` | Allowlist of permitted HTML5 tags forwarded to React |
16
+ | `STRIP_ELEMENTS` | Tags removed entirely at the HAST level |
17
+ | `EVENT_HANDLER_ATTR_RE` | Matches `on*` attribute names |
18
+ | `JAVASCRIPT_URL_RE` / `DATA_URL_RE` | Detect unsafe URL schemes |
19
+ | `TAG_LIKE_REGEX` | Parses HTML-like tags in markdown source |
20
+
21
+ ### Mermaid Support
22
+ - `mermaidStyles` — Responsive CSS for Mermaid SVG diagrams using DM Sans font.
23
+
24
+ ## Usage Example
25
+
26
+ ```typescript
27
+ import { SimpleMarkdownRenderer } from './simple-markdown-renderer';
28
+
29
+ // Basic usage — content is sanitized automatically
30
+ <SimpleMarkdownRenderer
31
+ content="## Hello\n\nThis is **LLM-generated** markdown with `code`."
32
+ />
33
+
34
+ // The sanitizer prevents XSS from LLM output automatically:
35
+ // "<script>alert(1)</script>" → stripped
36
+ // "<their> tag" → escaped to &lt;their&gt;
37
+ // "javascript:alert(1)" href → removed
38
+ ```
39
+
40
+ > **Note:** This renderer is designed specifically for untrusted LLM output. The sanitization pipeline runs in layers: text pre-processing → `rehype-raw` → `rehypeStripUnsafe` → `rehype-highlight`, ensuring no XSS vectors survive even if one layer is bypassed. Community support is available on the [OpenMSP Slack](https://join.slack.com/t/openmsp/shared_invite/zt-36bl7mx0h-3~U2nFH6nqHqoTPXMaHEHA).
@@ -174,6 +174,7 @@ export * from './ticket-attachments-list'
174
174
  export * from './ticket-note-card'
175
175
  export * from './ticket-notes-section'
176
176
  export * from './marquee-wall'
177
- export * from './markdown'
177
+ export * from './simple-markdown-renderer'
178
+ export { RichMarkdownRenderer, type RichMarkdownRendererProps } from './rich-markdown-renderer'
178
179
  export * from './filter-pill-row'
179
180
 
@@ -4,7 +4,7 @@ import React, { useState } from 'react';
4
4
  import { Badge } from './badge';
5
5
  import { ChevronDown } from 'lucide-react';
6
6
  import { FadePreview } from './fade-preview';
7
- import { RichMarkdownRenderer } from './markdown';
7
+ import { RichMarkdownRenderer } from './rich-markdown-renderer';
8
8
  import type { ChangelogEntry } from '../../types/product-release';
9
9
 
10
10
  interface ReleaseChangelogSectionProps {