orcheo-studio 0.21.1

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 (329) hide show
  1. package/.bumpversion.cfg +14 -0
  2. package/.eslintrc +1 -0
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +60 -0
  5. package/bin/orcheo-studio.js +39 -0
  6. package/components.json +21 -0
  7. package/dist/assets/arc-BbeTokFd.js +1 -0
  8. package/dist/assets/architectureDiagram-VXUJARFQ-CN00R9LC.js +36 -0
  9. package/dist/assets/avatar-01-CIAd4XAq.svg +1 -0
  10. package/dist/assets/avatar-02-BkgLJWQZ.svg +1 -0
  11. package/dist/assets/avatar-03-DVVcnD3b.svg +1 -0
  12. package/dist/assets/avatar-04-ydqFTDdh.svg +1 -0
  13. package/dist/assets/avatar-05-CSIhgJow.svg +1 -0
  14. package/dist/assets/avatar-06-B-h1Nz9Y.svg +1 -0
  15. package/dist/assets/avatar-07-BgkDZuBW.svg +1 -0
  16. package/dist/assets/avatar-08-C5KZjVH6.svg +1 -0
  17. package/dist/assets/avatar-09-2EGeSlPh.svg +1 -0
  18. package/dist/assets/avatar-10-DRf4ZGD2.svg +1 -0
  19. package/dist/assets/avatar-11-CEzBCpib.svg +1 -0
  20. package/dist/assets/avatar-12-COVngNEy.svg +1 -0
  21. package/dist/assets/avatar-13-D1i1tZVO.svg +1 -0
  22. package/dist/assets/avatar-14-B68CNAEs.svg +1 -0
  23. package/dist/assets/avatar-15-B9NsRNUX.svg +1 -0
  24. package/dist/assets/avatar-16-DQ_JJRGR.svg +1 -0
  25. package/dist/assets/avatar-17-DfDJkGv5.svg +1 -0
  26. package/dist/assets/avatar-18-BuxiqOaJ.svg +1 -0
  27. package/dist/assets/avatar-19-C2mJfrwW.svg +1 -0
  28. package/dist/assets/avatar-20-DPE_yE1a.svg +1 -0
  29. package/dist/assets/avatar-21-DbB0Lj6t.svg +1 -0
  30. package/dist/assets/blockDiagram-VD42YOAC-BPpieIRz.js +122 -0
  31. package/dist/assets/c4Diagram-YG6GDRKO-DAhuY1fj.js +10 -0
  32. package/dist/assets/channel-DtVQHWfl.js +1 -0
  33. package/dist/assets/chunk-4BX2VUAB-7RJQCroR.js +1 -0
  34. package/dist/assets/chunk-55IACEB6-CEN5yOA_.js +1 -0
  35. package/dist/assets/chunk-B4BG7PRW-vdlAz_3Q.js +165 -0
  36. package/dist/assets/chunk-DI55MBZ5-BTmKjGVg.js +220 -0
  37. package/dist/assets/chunk-FMBD7UC4-CwWvFfrg.js +15 -0
  38. package/dist/assets/chunk-QN33PNHL-XH90lUUN.js +1 -0
  39. package/dist/assets/chunk-QZHKN3VN-DMoMVES0.js +1 -0
  40. package/dist/assets/chunk-TZMSLE5B-Bx2XTXDY.js +1 -0
  41. package/dist/assets/classDiagram-2ON5EDUG-pw6P8q-u.js +1 -0
  42. package/dist/assets/classDiagram-v2-WZHVMYZB-pw6P8q-u.js +1 -0
  43. package/dist/assets/clone-DJq6GzHg.js +1 -0
  44. package/dist/assets/cose-bilkent-S5V4N54A-DS1MNwZB.js +1 -0
  45. package/dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  46. package/dist/assets/dagre-6UL2VRFP-DdklXSXB.js +4 -0
  47. package/dist/assets/defaultLocale-C4B-KCzX.js +1 -0
  48. package/dist/assets/diagram-PSM6KHXK-BKBo8pqg.js +24 -0
  49. package/dist/assets/diagram-QEK2KX5R-DaavZhFO.js +43 -0
  50. package/dist/assets/diagram-S2PKOQOG-DkTwknYd.js +24 -0
  51. package/dist/assets/erDiagram-Q2GNP2WA-ClR5qEsI.js +60 -0
  52. package/dist/assets/flowDiagram-NV44I4VS-Cxt_sJHB.js +162 -0
  53. package/dist/assets/ganttDiagram-JELNMOA3-CIbs3JPJ.js +267 -0
  54. package/dist/assets/gitGraphDiagram-V2S2FVAM-DmqLh_uo.js +65 -0
  55. package/dist/assets/graph-zo28rS-a.js +1 -0
  56. package/dist/assets/index-B0_h2wCA.css +1 -0
  57. package/dist/assets/index-Be29_rJf.js +775 -0
  58. package/dist/assets/infoDiagram-HS3SLOUP-D9_rMkAf.js +2 -0
  59. package/dist/assets/init-Gi6I4Gst.js +1 -0
  60. package/dist/assets/isUndefined-C59bc74c.js +1 -0
  61. package/dist/assets/journeyDiagram-XKPGCS4Q-4ZuggLXE.js +139 -0
  62. package/dist/assets/kanban-definition-3W4ZIXB7-BQDNrhHL.js +89 -0
  63. package/dist/assets/katex-CBSAILhF.js +261 -0
  64. package/dist/assets/layout-CXbNm-Yo.js +1 -0
  65. package/dist/assets/linear-DQWATg1F.js +1 -0
  66. package/dist/assets/min-DJjRzMm8.js +1 -0
  67. package/dist/assets/mindmap-definition-VGOIOE7T-DiZQmsHT.js +68 -0
  68. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  69. package/dist/assets/pieDiagram-ADFJNKIX-Bkju7jCD.js +30 -0
  70. package/dist/assets/quadrantDiagram-AYHSOK5B-CIB47UvU.js +7 -0
  71. package/dist/assets/requirementDiagram-UZGBJVZJ-BSB3uACk.js +64 -0
  72. package/dist/assets/sankeyDiagram-TZEHDZUN-rB8wD2kd.js +10 -0
  73. package/dist/assets/sequenceDiagram-WL72ISMW-Cd9s3Q_1.js +145 -0
  74. package/dist/assets/stateDiagram-FKZM4ZOC-zAxtjcM9.js +1 -0
  75. package/dist/assets/stateDiagram-v2-4FDKWEC3-C4DctH65.js +1 -0
  76. package/dist/assets/timeline-definition-IT6M3QCI-Et89F1F3.js +61 -0
  77. package/dist/assets/treemap-GDKQZRPO-6mZVX2Gv.js +162 -0
  78. package/dist/assets/xychartDiagram-PRI3JC2R-CgyY8dNz.js +7 -0
  79. package/dist/favicon.ico +0 -0
  80. package/dist/index.html +19 -0
  81. package/dist/robots.txt +2 -0
  82. package/eslint.config.js +49 -0
  83. package/index.html +18 -0
  84. package/package.json +183 -0
  85. package/postcss.config.js +6 -0
  86. package/public/favicon.ico +0 -0
  87. package/public/robots.txt +2 -0
  88. package/src/App.tsx +115 -0
  89. package/src/assets/avatars/avatar-01.svg +1 -0
  90. package/src/assets/avatars/avatar-02.svg +1 -0
  91. package/src/assets/avatars/avatar-03.svg +1 -0
  92. package/src/assets/avatars/avatar-04.svg +1 -0
  93. package/src/assets/avatars/avatar-05.svg +1 -0
  94. package/src/assets/avatars/avatar-06.svg +1 -0
  95. package/src/assets/avatars/avatar-07.svg +1 -0
  96. package/src/assets/avatars/avatar-08.svg +1 -0
  97. package/src/assets/avatars/avatar-09.svg +1 -0
  98. package/src/assets/avatars/avatar-10.svg +1 -0
  99. package/src/assets/avatars/avatar-11.svg +1 -0
  100. package/src/assets/avatars/avatar-12.svg +1 -0
  101. package/src/assets/avatars/avatar-13.svg +1 -0
  102. package/src/assets/avatars/avatar-14.svg +1 -0
  103. package/src/assets/avatars/avatar-15.svg +1 -0
  104. package/src/assets/avatars/avatar-16.svg +1 -0
  105. package/src/assets/avatars/avatar-17.svg +1 -0
  106. package/src/assets/avatars/avatar-18.svg +1 -0
  107. package/src/assets/avatars/avatar-19.svg +1 -0
  108. package/src/assets/avatars/avatar-20.svg +1 -0
  109. package/src/assets/avatars/avatar-21.svg +1 -0
  110. package/src/assets/avatars/index.ts +99 -0
  111. package/src/design-system/ui/alert-dialog.tsx +141 -0
  112. package/src/design-system/ui/alert.tsx +59 -0
  113. package/src/design-system/ui/avatar.tsx +51 -0
  114. package/src/design-system/ui/badge.tsx +38 -0
  115. package/src/design-system/ui/button.tsx +59 -0
  116. package/src/design-system/ui/card.tsx +83 -0
  117. package/src/design-system/ui/dialog.tsx +122 -0
  118. package/src/design-system/ui/dropdown-menu.tsx +201 -0
  119. package/src/design-system/ui/input.tsx +22 -0
  120. package/src/design-system/ui/label.tsx +26 -0
  121. package/src/design-system/ui/scroll-area.tsx +48 -0
  122. package/src/design-system/ui/select.tsx +159 -0
  123. package/src/design-system/ui/separator.tsx +31 -0
  124. package/src/design-system/ui/sheet.tsx +141 -0
  125. package/src/design-system/ui/skeleton.tsx +15 -0
  126. package/src/design-system/ui/switch.tsx +29 -0
  127. package/src/design-system/ui/table.tsx +120 -0
  128. package/src/design-system/ui/tabs.tsx +55 -0
  129. package/src/design-system/ui/textarea.tsx +22 -0
  130. package/src/design-system/ui/toast.tsx +132 -0
  131. package/src/design-system/ui/toaster.tsx +35 -0
  132. package/src/design-system/ui/toggle-group.tsx +61 -0
  133. package/src/design-system/ui/toggle.tsx +46 -0
  134. package/src/design-system/ui/tooltip.tsx +32 -0
  135. package/src/features/MODULES.md +199 -0
  136. package/src/features/account/components/settings/appearance-settings-tab.tsx +24 -0
  137. package/src/features/account/components/theme-settings.tsx +70 -0
  138. package/src/features/account/components/use-theme-preferences.ts +106 -0
  139. package/src/features/account/pages/profile/components/profile-general-tab.tsx +89 -0
  140. package/src/features/account/pages/profile/types.ts +7 -0
  141. package/src/features/account/pages/profile.tsx +71 -0
  142. package/src/features/account/pages/service-tokens.tsx +522 -0
  143. package/src/features/account/pages/settings.tsx +42 -0
  144. package/src/features/account/pages/workspace-management.tsx +63 -0
  145. package/src/features/account/pages/workspace-members.tsx +335 -0
  146. package/src/features/auth/components/auto-login.tsx +51 -0
  147. package/src/features/auth/components/require-auth.tsx +56 -0
  148. package/src/features/auth/lib/auth-session.ts +448 -0
  149. package/src/features/auth/lib/oidc-client.ts +565 -0
  150. package/src/features/auth/pages/login.tsx +24 -0
  151. package/src/features/auth/pages/oauth-callback.tsx +63 -0
  152. package/src/features/chatkit/components/chatkit-surface.tsx +60 -0
  153. package/src/features/chatkit/components/public-chat-config.ts +70 -0
  154. package/src/features/chatkit/components/public-chat-error-boundary.tsx +74 -0
  155. package/src/features/chatkit/components/public-chat-widget.tsx +150 -0
  156. package/src/features/chatkit/components/studio-chat-bubble.tsx +451 -0
  157. package/src/features/chatkit/lib/chatkit-attachments.ts +31 -0
  158. package/src/features/chatkit/lib/chatkit-client.ts +195 -0
  159. package/src/features/chatkit/lib/chatkit-theme.ts +20 -0
  160. package/src/features/chatkit/lib/telemetry.ts +29 -0
  161. package/src/features/chatkit/lib/workflow-session.ts +70 -0
  162. package/src/features/chatkit/pages/public-chat.tsx +445 -0
  163. package/src/features/shared/components/chat-interface-options.ts +325 -0
  164. package/src/features/shared/components/chat-interface.types.ts +47 -0
  165. package/src/features/shared/components/top-navigation/account-menu.tsx +172 -0
  166. package/src/features/shared/components/top-navigation/active-workspace-indicator.tsx +280 -0
  167. package/src/features/shared/components/top-navigation/studio-brand.tsx +59 -0
  168. package/src/features/shared/components/top-navigation/top-navigation-types.ts +22 -0
  169. package/src/features/shared/components/top-navigation/version-status.tsx +280 -0
  170. package/src/features/shared/components/top-navigation.tsx +42 -0
  171. package/src/features/shared/components/workspace-bootstrap-gate.tsx +235 -0
  172. package/src/features/workflow/components/dialogs/add-credential-dialog.tsx +245 -0
  173. package/src/features/workflow/components/dialogs/confirm-delete-workflow-dialog.tsx +52 -0
  174. package/src/features/workflow/components/dialogs/credential-access-badge.tsx +34 -0
  175. package/src/features/workflow/components/dialogs/credential-status-badge.tsx +45 -0
  176. package/src/features/workflow/components/dialogs/credentials-table.tsx +453 -0
  177. package/src/features/workflow/components/dialogs/credentials-vault.tsx +85 -0
  178. package/src/features/workflow/components/dialogs/edit-credential-dialog.tsx +264 -0
  179. package/src/features/workflow/components/dialogs/update-workflow-dialog.tsx +214 -0
  180. package/src/features/workflow/components/dialogs/upload-workflow-dialog.tsx +288 -0
  181. package/src/features/workflow/components/forms/schema-config-form.tsx +41 -0
  182. package/src/features/workflow/components/layouts/sidebar-layout.tsx +288 -0
  183. package/src/features/workflow/components/layouts/use-sidebar-resize.ts +164 -0
  184. package/src/features/workflow/components/layouts/workflow-page-layout.tsx +69 -0
  185. package/src/features/workflow/components/panels/json-object-field.tsx +138 -0
  186. package/src/features/workflow/components/panels/rjsf-basic-widgets.tsx +21 -0
  187. package/src/features/workflow/components/panels/rjsf-input-widgets.tsx +105 -0
  188. package/src/features/workflow/components/panels/rjsf-templates.tsx +147 -0
  189. package/src/features/workflow/components/panels/rjsf-text-widgets.tsx +139 -0
  190. package/src/features/workflow/components/panels/rjsf-theme.tsx +10 -0
  191. package/src/features/workflow/components/panels/schema-dnd.ts +79 -0
  192. package/src/features/workflow/components/panels/workflow-diff-dialog.tsx +207 -0
  193. package/src/features/workflow/components/panels/workflow-history-filters.tsx +62 -0
  194. package/src/features/workflow/components/panels/workflow-history-footer.tsx +28 -0
  195. package/src/features/workflow/components/panels/workflow-history-header.tsx +47 -0
  196. package/src/features/workflow/components/panels/workflow-history-table.tsx +148 -0
  197. package/src/features/workflow/components/panels/workflow-history.tsx +150 -0
  198. package/src/features/workflow/components/panels/workflow-tabs.tsx +29 -0
  199. package/src/features/workflow/components/trace/agent-prism/Avatar.tsx +146 -0
  200. package/src/features/workflow/components/trace/agent-prism/Badge.tsx +95 -0
  201. package/src/features/workflow/components/trace/agent-prism/BrandLogo.tsx +102 -0
  202. package/src/features/workflow/components/trace/agent-prism/Button.tsx +124 -0
  203. package/src/features/workflow/components/trace/agent-prism/CollapseAndExpandControls.tsx +45 -0
  204. package/src/features/workflow/components/trace/agent-prism/CollapsibleSection.tsx +124 -0
  205. package/src/features/workflow/components/trace/agent-prism/CopyButton.tsx +63 -0
  206. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsView.tsx +146 -0
  207. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewAttributesTab.tsx +125 -0
  208. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewContentViewer.tsx +51 -0
  209. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewHeader.tsx +100 -0
  210. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewInputOutputTab.tsx +401 -0
  211. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewJsonOutput.tsx +33 -0
  212. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewRawDataTab.tsx +27 -0
  213. package/src/features/workflow/components/trace/agent-prism/IconButton.tsx +75 -0
  214. package/src/features/workflow/components/trace/agent-prism/PriceBadge.tsx +14 -0
  215. package/src/features/workflow/components/trace/agent-prism/SearchInput.tsx +17 -0
  216. package/src/features/workflow/components/trace/agent-prism/SpanBadge.tsx +54 -0
  217. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCard.tsx +480 -0
  218. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardBadges.tsx +23 -0
  219. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardConnector.tsx +36 -0
  220. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardTimeline.tsx +60 -0
  221. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardToggle.tsx +39 -0
  222. package/src/features/workflow/components/trace/agent-prism/SpanStatus.tsx +80 -0
  223. package/src/features/workflow/components/trace/agent-prism/TabSelector.tsx +35 -0
  224. package/src/features/workflow/components/trace/agent-prism/Tabs.tsx +140 -0
  225. package/src/features/workflow/components/trace/agent-prism/TextInput.tsx +143 -0
  226. package/src/features/workflow/components/trace/agent-prism/TimestampBadge.tsx +22 -0
  227. package/src/features/workflow/components/trace/agent-prism/TokensBadge.tsx +27 -0
  228. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceList.tsx +123 -0
  229. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItem.tsx +86 -0
  230. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItemHeader.tsx +37 -0
  231. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewer.tsx +208 -0
  232. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerDesktopLayout.tsx +99 -0
  233. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerMobileLayout.tsx +103 -0
  234. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerPlaceholder.tsx +5 -0
  235. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerSearchAndControls.tsx +30 -0
  236. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerTreeViewContainer.tsx +76 -0
  237. package/src/features/workflow/components/trace/agent-prism/TraceViewer/useTraceSelection.ts +186 -0
  238. package/src/features/workflow/components/trace/agent-prism/TreeView.tsx +73 -0
  239. package/src/features/workflow/components/trace/agent-prism/index.ts +7 -0
  240. package/src/features/workflow/components/trace/agent-prism/shared.ts +170 -0
  241. package/src/features/workflow/components/trace/agent-prism/theme/index.ts +101 -0
  242. package/src/features/workflow/components/trace/agent-prism/theme/theme.css +247 -0
  243. package/src/features/workflow/data/templates/assets/vibe-agent/config.json +5 -0
  244. package/src/features/workflow/data/templates/candidate-badges.ts +138 -0
  245. package/src/features/workflow/data/templates/index.ts +29 -0
  246. package/src/features/workflow/data/templates/template-definition.ts +77 -0
  247. package/src/features/workflow/data/templates/template-owner.ts +7 -0
  248. package/src/features/workflow/data/workflow-data.ts +8 -0
  249. package/src/features/workflow/data/workflow-types.ts +57 -0
  250. package/src/features/workflow/lib/mermaid-renderer.ts +334 -0
  251. package/src/features/workflow/lib/workflow-diff.ts +191 -0
  252. package/src/features/workflow/lib/workflow-execution-builders.ts +103 -0
  253. package/src/features/workflow/lib/workflow-execution-formatters.ts +145 -0
  254. package/src/features/workflow/lib/workflow-execution-storage.ts +63 -0
  255. package/src/features/workflow/lib/workflow-execution.types.ts +80 -0
  256. package/src/features/workflow/lib/workflow-storage-api.ts +581 -0
  257. package/src/features/workflow/lib/workflow-storage-helpers.ts +373 -0
  258. package/src/features/workflow/lib/workflow-storage-versioning.ts +127 -0
  259. package/src/features/workflow/lib/workflow-storage.constants.ts +21 -0
  260. package/src/features/workflow/lib/workflow-storage.ts +482 -0
  261. package/src/features/workflow/lib/workflow-storage.types.ts +261 -0
  262. package/src/features/workflow/pages/workflow/components/settings-tab-content.tsx +428 -0
  263. package/src/features/workflow/pages/workflow/components/trace-tab-content.tsx +183 -0
  264. package/src/features/workflow/pages/workflow/components/workflow-config-sheet.tsx +207 -0
  265. package/src/features/workflow/pages/workflow/components/workflow-config-sheet.utils.ts +275 -0
  266. package/src/features/workflow/pages/workflow/components/workflow-layout.tsx +143 -0
  267. package/src/features/workflow/pages/workflow/components/workflow-tab-content.tsx +766 -0
  268. package/src/features/workflow/pages/workflow/handlers/credentials.ts +338 -0
  269. package/src/features/workflow/pages/workflow/helpers/execution.ts +39 -0
  270. package/src/features/workflow/pages/workflow/helpers/trace.ts +838 -0
  271. package/src/features/workflow/pages/workflow/helpers/types.ts +28 -0
  272. package/src/features/workflow/pages/workflow/hooks/controller/build-layout-props.ts +171 -0
  273. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-controller.ts +19 -0
  274. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-core.ts +84 -0
  275. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-execution-controller.ts +167 -0
  276. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-lifecycle.ts +37 -0
  277. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-resources.ts +57 -0
  278. package/src/features/workflow/pages/workflow/hooks/execution-log-helpers.ts +75 -0
  279. package/src/features/workflow/pages/workflow/hooks/execution-node-status.ts +46 -0
  280. package/src/features/workflow/pages/workflow/hooks/execution-record-updater.ts +119 -0
  281. package/src/features/workflow/pages/workflow/hooks/execution-record.ts +31 -0
  282. package/src/features/workflow/pages/workflow/hooks/execution-runtime-updates.ts +96 -0
  283. package/src/features/workflow/pages/workflow/hooks/use-execution-trace.ts +512 -0
  284. package/src/features/workflow/pages/workflow/hooks/use-execution-updates.ts +125 -0
  285. package/src/features/workflow/pages/workflow/hooks/use-pause-workflow.ts +70 -0
  286. package/src/features/workflow/pages/workflow/hooks/use-studio-ui-state.ts +10 -0
  287. package/src/features/workflow/pages/workflow/hooks/use-workflow-chat.ts +212 -0
  288. package/src/features/workflow/pages/workflow/hooks/use-workflow-credential-readiness.ts +72 -0
  289. package/src/features/workflow/pages/workflow/hooks/use-workflow-credentials.ts +167 -0
  290. package/src/features/workflow/pages/workflow/hooks/use-workflow-execution-state.ts +20 -0
  291. package/src/features/workflow/pages/workflow/hooks/use-workflow-listeners.ts +182 -0
  292. package/src/features/workflow/pages/workflow/hooks/use-workflow-loader.ts +236 -0
  293. package/src/features/workflow/pages/workflow/hooks/use-workflow-metadata-state.ts +56 -0
  294. package/src/features/workflow/pages/workflow/hooks/use-workflow-saver.ts +191 -0
  295. package/src/features/workflow/pages/workflow/hooks/use-workflow-storage-listener.ts +81 -0
  296. package/src/features/workflow/pages/workflow/hooks/workflow-runner-websocket.ts +150 -0
  297. package/src/features/workflow/pages/workflow-gallery/types.ts +3 -0
  298. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-actions.ts +223 -0
  299. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-state.ts +206 -0
  300. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery.ts +14 -0
  301. package/src/features/workflow/pages/workflow-gallery/workflow-card-size.ts +8 -0
  302. package/src/features/workflow/pages/workflow-gallery/workflow-card.tsx +327 -0
  303. package/src/features/workflow/pages/workflow-gallery/workflow-gallery-tabs.tsx +173 -0
  304. package/src/features/workflow/pages/workflow-gallery.tsx +96 -0
  305. package/src/features/workflow/pages/workflow.tsx +119 -0
  306. package/src/features/workflow/types/credential-vault.ts +52 -0
  307. package/src/hooks/browser-context-provider.tsx +19 -0
  308. package/src/hooks/use-browser-context.ts +188 -0
  309. package/src/hooks/use-color-scheme.ts +77 -0
  310. package/src/hooks/use-credential-vault.ts +442 -0
  311. package/src/hooks/use-page-context.ts +39 -0
  312. package/src/hooks/use-toast.ts +182 -0
  313. package/src/hooks/use-uploads-allowed.ts +28 -0
  314. package/src/index.css +95 -0
  315. package/src/lib/api.ts +445 -0
  316. package/src/lib/auth-fetch.ts +35 -0
  317. package/src/lib/config.ts +102 -0
  318. package/src/lib/theme.ts +109 -0
  319. package/src/lib/utils.ts +6 -0
  320. package/src/lib/workspace-routing.ts +67 -0
  321. package/src/lib/workspace-session.ts +66 -0
  322. package/src/lib/workspace-slug.ts +10 -0
  323. package/src/main.tsx +28 -0
  324. package/src/vite-env.d.ts +17 -0
  325. package/tailwind.config.js +153 -0
  326. package/tsconfig.app.json +30 -0
  327. package/tsconfig.json +16 -0
  328. package/tsconfig.node.json +21 -0
  329. package/vite.config.ts +122 -0
@@ -0,0 +1,138 @@
1
+ import { seededAvatarId } from "@/assets/avatars";
2
+ import type { Workflow } from "../workflow-types";
3
+ import type { StoredWorkflow } from "../../lib/workflow-storage.types";
4
+ import type {
5
+ WorkflowTemplateDefinition,
6
+ WorkflowTemplateMetadata,
7
+ } from "./template-definition";
8
+
9
+ export interface CandidateBadgeSpec {
10
+ id: string;
11
+ /** Original candidate id from the server (used by the onboard endpoint). */
12
+ candidateId: string;
13
+ name: string;
14
+ handle: string;
15
+ subtitle?: string;
16
+ description?: string;
17
+ /** Avatar ID ("avatar-01" … "avatar-21"), "random", or absent for a seeded random avatar. */
18
+ avatar?: string;
19
+ notes?: string | null;
20
+ mermaid?: string | null;
21
+ /** Raw snake_case metadata dict from the colleague-candidates frontmatter. */
22
+ rawMetadata?: Record<string, unknown> | null;
23
+ }
24
+
25
+ export interface CandidateBadgeDefinition extends CandidateBadgeSpec {
26
+ workflow: Workflow;
27
+ templateDefinition: WorkflowTemplateDefinition;
28
+ }
29
+
30
+ const toStringArray = (value: unknown): string[] | undefined => {
31
+ if (!Array.isArray(value)) {
32
+ return undefined;
33
+ }
34
+ const strings = value.filter((v): v is string => typeof v === "string");
35
+ return strings.length > 0 ? strings : undefined;
36
+ };
37
+
38
+ const mapRawMetadata = (
39
+ raw: Record<string, unknown>,
40
+ ): WorkflowTemplateMetadata => ({
41
+ requiredPlugins: toStringArray(raw.required_plugins),
42
+ validatedProviderApi:
43
+ typeof raw.validated_provider_api === "string"
44
+ ? raw.validated_provider_api
45
+ : undefined,
46
+ replyNodeContracts: toStringArray(raw.reply_node_contracts),
47
+ templateVersion:
48
+ typeof raw.template_version === "string" ? raw.template_version : undefined,
49
+ minOrcheoVersion:
50
+ typeof raw.min_orcheo_version === "string"
51
+ ? raw.min_orcheo_version
52
+ : undefined,
53
+ });
54
+
55
+ const buildCandidateWorkflow = (
56
+ spec: CandidateBadgeSpec,
57
+ existingHandles: Set<string>,
58
+ ): Workflow => {
59
+ // Preserve original handle if no conflict exists, otherwise let backend generate unique handle
60
+ const preserveHandle =
61
+ spec.handle && !existingHandles.has(spec.handle) ? spec.handle : undefined;
62
+
63
+ const avatarId =
64
+ spec.avatar && spec.avatar !== "random"
65
+ ? spec.avatar
66
+ : seededAvatarId(spec.id);
67
+
68
+ return {
69
+ id: spec.id,
70
+ handle: preserveHandle,
71
+ name: spec.name,
72
+ description: spec.description,
73
+ avatarEmoji: avatarId,
74
+ createdAt: "2026-01-01T00:00:00Z",
75
+ updatedAt: "2026-01-01T00:00:00Z",
76
+ owner: {
77
+ id: `${spec.id}-owner`,
78
+ name: spec.name,
79
+ avatar: "",
80
+ },
81
+ tags: ["template"],
82
+ nodes: [],
83
+ edges: [],
84
+ versions: spec.mermaid
85
+ ? [{ id: `${spec.id}-v1`, mermaid: spec.mermaid }]
86
+ : [],
87
+ };
88
+ };
89
+
90
+ const buildCandidateBadge = (
91
+ spec: CandidateBadgeSpec,
92
+ existingHandles: Set<string>,
93
+ ): CandidateBadgeDefinition => {
94
+ const workflow = buildCandidateWorkflow(spec, existingHandles);
95
+ const templateDefinition: WorkflowTemplateDefinition = {
96
+ workflow,
97
+ script: "",
98
+ entrypoint: undefined,
99
+ runnableConfig: null,
100
+ notes: spec.notes ?? "",
101
+ metadata: spec.rawMetadata ? mapRawMetadata(spec.rawMetadata) : undefined,
102
+ };
103
+ return { ...spec, workflow, templateDefinition };
104
+ };
105
+
106
+ // Candidates are sourced at runtime from the colleague-candidates repository
107
+ // (via the backend /api/candidates endpoint), so this registry is populated
108
+ // after fetch rather than at module load.
109
+ let candidateBadges: CandidateBadgeDefinition[] = [];
110
+
111
+ export const setCandidateBadges = (
112
+ specs: CandidateBadgeSpec[],
113
+ existingWorkflows: StoredWorkflow[] = [],
114
+ ): void => {
115
+ // Create set of existing handles to check for conflicts
116
+ const existingHandles = new Set<string>(
117
+ existingWorkflows
118
+ .map((w) => w.handle)
119
+ .filter((handle): handle is string => Boolean(handle)),
120
+ );
121
+
122
+ candidateBadges = specs.map((spec) =>
123
+ buildCandidateBadge(spec, existingHandles),
124
+ );
125
+ };
126
+
127
+ export const getCandidateWorkflows = (): Workflow[] =>
128
+ candidateBadges.map((badge) => badge.workflow);
129
+
130
+ export const getCandidateBadgeDefinition = (
131
+ workflowId: string,
132
+ ): CandidateBadgeDefinition | undefined =>
133
+ candidateBadges.find((badge) => badge.workflow.id === workflowId);
134
+
135
+ export const getCandidateTemplateDefinition = (
136
+ templateId: string,
137
+ ): WorkflowTemplateDefinition | undefined =>
138
+ getCandidateBadgeDefinition(templateId)?.templateDefinition;
@@ -0,0 +1,29 @@
1
+ import { Workflow } from "../workflow-types";
2
+ import {
3
+ assertWorkflowTemplateCompatibility,
4
+ type WorkflowTemplateDefinition,
5
+ } from "./template-definition";
6
+ import { getCandidateTemplateDefinition } from "./candidate-badges";
7
+
8
+ export const SAMPLE_WORKFLOWS: Workflow[] = [];
9
+
10
+ export const GALLERY_TEMPLATE_WORKFLOWS: Workflow[] = [];
11
+
12
+ export const WORKFLOW_TEMPLATE_DEFINITIONS: WorkflowTemplateDefinition[] = [];
13
+
14
+ const TEMPLATE_BY_ID = new Map(
15
+ WORKFLOW_TEMPLATE_DEFINITIONS.map((definition) => [
16
+ definition.workflow.id,
17
+ definition,
18
+ ]),
19
+ );
20
+
21
+ export const getWorkflowTemplateDefinition = (
22
+ templateId: string,
23
+ ): WorkflowTemplateDefinition | undefined => {
24
+ return (
25
+ TEMPLATE_BY_ID.get(templateId) ?? getCandidateTemplateDefinition(templateId)
26
+ );
27
+ };
28
+
29
+ export { assertWorkflowTemplateCompatibility };
@@ -0,0 +1,77 @@
1
+ import type { WorkflowRunnableConfig } from "@features/workflow/lib/workflow-storage.types";
2
+ import type { Workflow } from "../workflow-types";
3
+
4
+ export interface WorkflowTemplateMetadata {
5
+ templateVersion?: string;
6
+ minOrcheoVersion?: string;
7
+ validatedProviderApi?: string;
8
+ validationDate?: string;
9
+ owner?: string;
10
+ acceptanceCriteria?: string[];
11
+ revalidationTriggers?: string[];
12
+ replyNodeContracts?: string[];
13
+ requiredPlugins?: string[];
14
+ }
15
+
16
+ export interface WorkflowTemplateDefinition {
17
+ workflow: Workflow;
18
+ script: string;
19
+ entrypoint?: string;
20
+ runnableConfig?: WorkflowRunnableConfig | null;
21
+ notes: string;
22
+ metadata?: WorkflowTemplateMetadata;
23
+ }
24
+
25
+ const CURRENT_PROVIDER_APIS = new Set([
26
+ "telegram-bot-api",
27
+ "discord-gateway-v10",
28
+ "qq-bot-api-v2",
29
+ "private-bot-listener-suite-2026-03-11",
30
+ "wecom-lark-listener-plugin-suite-2026-03-16",
31
+ "openclaw-wechat-plugin-2026-03-22",
32
+ ]);
33
+
34
+ const CURRENT_REPLY_NODE_CONTRACTS = new Set([
35
+ "MessageTelegramNode@1",
36
+ "MessageDiscordNode@1",
37
+ "MessageQQNode@1",
38
+ "WechatReplyNode@1",
39
+ ]);
40
+
41
+ export const getWorkflowTemplateCompatibilityIssues = (
42
+ definition: WorkflowTemplateDefinition,
43
+ ): string[] => {
44
+ const metadata = definition.metadata;
45
+ if (!metadata) {
46
+ return [];
47
+ }
48
+
49
+ const issues: string[] = [];
50
+ if (
51
+ metadata.validatedProviderApi &&
52
+ !CURRENT_PROVIDER_APIS.has(metadata.validatedProviderApi)
53
+ ) {
54
+ issues.push(
55
+ `provider API '${metadata.validatedProviderApi}' requires revalidation`,
56
+ );
57
+ }
58
+
59
+ for (const contract of metadata.replyNodeContracts ?? []) {
60
+ if (!CURRENT_REPLY_NODE_CONTRACTS.has(contract)) {
61
+ issues.push(`reply node contract '${contract}' requires revalidation`);
62
+ }
63
+ }
64
+ return issues;
65
+ };
66
+
67
+ export const assertWorkflowTemplateCompatibility = (
68
+ definition: WorkflowTemplateDefinition,
69
+ ): void => {
70
+ const issues = getWorkflowTemplateCompatibilityIssues(definition);
71
+ if (issues.length === 0) {
72
+ return;
73
+ }
74
+ throw new Error(
75
+ `Template '${definition.workflow.id}' is out of date: ${issues.join("; ")}`,
76
+ );
77
+ };
@@ -0,0 +1,7 @@
1
+ import { Workflow } from "../workflow-types";
2
+
3
+ export const TEMPLATE_OWNER: Workflow["owner"] = {
4
+ id: "team-templates",
5
+ name: "Orcheo Templates",
6
+ avatar: "https://avatar.vercel.sh/templates",
7
+ };
@@ -0,0 +1,8 @@
1
+ export type { Workflow, WorkflowEdge, WorkflowNode } from "./workflow-types";
2
+ export {
3
+ assertWorkflowTemplateCompatibility,
4
+ GALLERY_TEMPLATE_WORKFLOWS,
5
+ SAMPLE_WORKFLOWS,
6
+ WORKFLOW_TEMPLATE_DEFINITIONS,
7
+ getWorkflowTemplateDefinition,
8
+ } from "./templates";
@@ -0,0 +1,57 @@
1
+ export interface WorkflowNode {
2
+ id: string;
3
+ type: string;
4
+ position: { x: number; y: number };
5
+ data: {
6
+ label: string;
7
+ description?: string;
8
+ status?: "idle" | "running" | "success" | "error";
9
+ isDisabled?: boolean;
10
+ backendType?: string;
11
+ [key: string]: unknown;
12
+ };
13
+ }
14
+
15
+ export interface WorkflowEdge {
16
+ id: string;
17
+ source: string;
18
+ target: string;
19
+ sourceHandle?: string | null;
20
+ targetHandle?: string | null;
21
+ label?: string;
22
+ type?: string;
23
+ animated?: boolean;
24
+ style?: Record<string, unknown>;
25
+ }
26
+
27
+ export interface WorkflowMermaidPreviewVersion {
28
+ id: string;
29
+ mermaid?: string | null;
30
+ templateId?: string;
31
+ }
32
+
33
+ export interface Workflow {
34
+ id: string;
35
+ handle?: string;
36
+ name: string;
37
+ description?: string;
38
+ avatarEmoji?: string | null;
39
+ draftAccess?: "personal" | "authenticated" | "workspace";
40
+ createdAt: string;
41
+ updatedAt: string;
42
+ sourceExample?: string;
43
+ owner: {
44
+ id: string;
45
+ name: string;
46
+ avatar: string;
47
+ };
48
+ tags: string[];
49
+ lastRun?: {
50
+ status: "success" | "error" | "running" | "idle";
51
+ timestamp: string;
52
+ duration: number;
53
+ };
54
+ nodes: WorkflowNode[];
55
+ edges: WorkflowEdge[];
56
+ versions?: WorkflowMermaidPreviewVersion[];
57
+ }
@@ -0,0 +1,334 @@
1
+ import mermaid from "mermaid";
2
+
3
+ const MAX_CONCURRENT_RENDERS = 3;
4
+ const MEMORY_CACHE_LIMIT = 150;
5
+ const SESSION_CACHE_LIMIT = 40;
6
+ const MAX_SESSION_SVG_LENGTH = 150_000;
7
+ const SESSION_STORAGE_KEY = "orcheo:workflow:mermaid-svg-cache:v1";
8
+
9
+ let mermaidInitialized = false;
10
+ let hydratedSessionCache = false;
11
+ let activeRenders = 0;
12
+
13
+ const renderQueue: Array<() => void> = [];
14
+ const inFlightRenders = new Map<string, Promise<string>>();
15
+ const memoryCache = new Map<string, string>();
16
+ const sessionCache = new Map<string, string>();
17
+
18
+ interface MermaidSessionCacheRecord {
19
+ key: string;
20
+ svg: string;
21
+ }
22
+
23
+ export interface MermaidRenderOptions {
24
+ source: string;
25
+ cacheKey: string;
26
+ renderId: string;
27
+ transformSvg?: (svg: string) => string;
28
+ }
29
+
30
+ const ensureMermaidInitialized = () => {
31
+ if (mermaidInitialized) {
32
+ return;
33
+ }
34
+
35
+ mermaid.initialize({
36
+ startOnLoad: false,
37
+ securityLevel: "strict",
38
+ theme: "neutral",
39
+ });
40
+ mermaidInitialized = true;
41
+ };
42
+
43
+ const trimCache = <T>(cache: Map<string, T>, maxEntries: number) => {
44
+ while (cache.size > maxEntries) {
45
+ const oldestKey = cache.keys().next().value;
46
+ if (oldestKey === undefined) {
47
+ break;
48
+ }
49
+ cache.delete(oldestKey);
50
+ }
51
+ };
52
+
53
+ const touchCacheEntry = <T>(cache: Map<string, T>, key: string, value: T) => {
54
+ if (cache.has(key)) {
55
+ cache.delete(key);
56
+ }
57
+ cache.set(key, value);
58
+ };
59
+
60
+ const isSessionStorageAvailable = (): boolean =>
61
+ typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
62
+
63
+ const logSessionCacheWarning = (
64
+ operation: "read" | "write",
65
+ error: unknown,
66
+ ) => {
67
+ console.warn(`Failed to ${operation} Mermaid SVG session cache`, error);
68
+ };
69
+
70
+ const readSessionCache = () => {
71
+ if (hydratedSessionCache || !isSessionStorageAvailable()) {
72
+ return;
73
+ }
74
+
75
+ hydratedSessionCache = true;
76
+
77
+ try {
78
+ const raw = window.sessionStorage.getItem(SESSION_STORAGE_KEY);
79
+ if (!raw) {
80
+ return;
81
+ }
82
+
83
+ const parsed = JSON.parse(raw) as MermaidSessionCacheRecord[] | undefined;
84
+ if (!Array.isArray(parsed)) {
85
+ return;
86
+ }
87
+
88
+ parsed.forEach((record) => {
89
+ if (
90
+ typeof record?.key === "string" &&
91
+ typeof record?.svg === "string" &&
92
+ record.key.length > 0 &&
93
+ record.svg.length > 0
94
+ ) {
95
+ touchCacheEntry(sessionCache, record.key, record.svg);
96
+ }
97
+ });
98
+
99
+ trimCache(sessionCache, SESSION_CACHE_LIMIT);
100
+ } catch (error) {
101
+ logSessionCacheWarning("read", error);
102
+ }
103
+ };
104
+
105
+ const writeSessionCache = () => {
106
+ if (!isSessionStorageAvailable()) {
107
+ return;
108
+ }
109
+
110
+ try {
111
+ const payload: MermaidSessionCacheRecord[] = Array.from(
112
+ sessionCache.entries(),
113
+ ).map(([key, svg]) => ({ key, svg }));
114
+
115
+ window.sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(payload));
116
+ } catch (error) {
117
+ logSessionCacheWarning("write", error);
118
+ }
119
+ };
120
+
121
+ const getCachedSvg = (cacheKey: string): string | null => {
122
+ const fromMemory = memoryCache.get(cacheKey);
123
+ if (fromMemory) {
124
+ touchCacheEntry(memoryCache, cacheKey, fromMemory);
125
+ return fromMemory;
126
+ }
127
+
128
+ readSessionCache();
129
+
130
+ const fromSession = sessionCache.get(cacheKey);
131
+ if (!fromSession) {
132
+ return null;
133
+ }
134
+
135
+ touchCacheEntry(sessionCache, cacheKey, fromSession);
136
+ touchCacheEntry(memoryCache, cacheKey, fromSession);
137
+ trimCache(memoryCache, MEMORY_CACHE_LIMIT);
138
+ return fromSession;
139
+ };
140
+
141
+ const storeCachedSvg = (cacheKey: string, svg: string) => {
142
+ touchCacheEntry(memoryCache, cacheKey, svg);
143
+ trimCache(memoryCache, MEMORY_CACHE_LIMIT);
144
+
145
+ if (svg.length > MAX_SESSION_SVG_LENGTH) {
146
+ return;
147
+ }
148
+
149
+ readSessionCache();
150
+ touchCacheEntry(sessionCache, cacheKey, svg);
151
+ trimCache(sessionCache, SESSION_CACHE_LIMIT);
152
+ writeSessionCache();
153
+ };
154
+
155
+ const acquireRenderSlot = async () => {
156
+ if (activeRenders < MAX_CONCURRENT_RENDERS) {
157
+ activeRenders += 1;
158
+ return;
159
+ }
160
+
161
+ await new Promise<void>((resolve) => {
162
+ renderQueue.push(() => {
163
+ activeRenders += 1;
164
+ resolve();
165
+ });
166
+ });
167
+ };
168
+
169
+ const releaseRenderSlot = () => {
170
+ activeRenders = Math.max(0, activeRenders - 1);
171
+ const next = renderQueue.shift();
172
+ if (next) {
173
+ next();
174
+ }
175
+ };
176
+
177
+ export const sanitizeMermaidIdPart = (value: string): string =>
178
+ value.replace(/[^a-zA-Z0-9_-]/g, "-");
179
+
180
+ export const forceMermaidLeftToRight = (source: string): string => {
181
+ const normalizedSource = source.trim();
182
+ if (!normalizedSource) {
183
+ return normalizedSource;
184
+ }
185
+
186
+ const withDirection = normalizedSource.replace(
187
+ /^(\s*(?:flowchart|graph)\s+)(?:TB|TD|BT|RL|LR)\b([^\n\r]*)/im,
188
+ "$1LR$2",
189
+ );
190
+ if (withDirection !== normalizedSource) {
191
+ return withDirection;
192
+ }
193
+
194
+ return normalizedSource.replace(/^(\s*(?:flowchart|graph))(\s*)$/im, "$1 LR");
195
+ };
196
+
197
+ const MERMAID_COLOR_ALIASES: ReadonlyArray<[RegExp, string]> = [
198
+ [/\bclassDef\s+default\s+fill:#eef4ff\b/gi, "classDef default fill:#f2f0ff"],
199
+ [/\bclassDef\s+last\s+fill:#94b8ff\b/gi, "classDef last fill:#bfb6fc"],
200
+ ];
201
+
202
+ export const normalizeMermaidPalette = (source: string): string =>
203
+ MERMAID_COLOR_ALIASES.reduce(
204
+ (normalized, [pattern, replacement]) =>
205
+ normalized.replace(pattern, replacement),
206
+ source,
207
+ );
208
+
209
+ export const hashMermaidSource = (value: string): string => {
210
+ let hash = 0x811c9dc5;
211
+ for (let index = 0; index < value.length; index += 1) {
212
+ hash ^= value.charCodeAt(index);
213
+ hash +=
214
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
215
+ }
216
+ return (hash >>> 0).toString(36);
217
+ };
218
+
219
+ export const buildMermaidCacheKey = (options: {
220
+ scope: string;
221
+ workflowId: string;
222
+ versionId: string;
223
+ source: string;
224
+ }): string => {
225
+ const normalizedSource = options.source.trim();
226
+ const sourceHash = hashMermaidSource(normalizedSource);
227
+ return [
228
+ sanitizeMermaidIdPart(options.scope),
229
+ sanitizeMermaidIdPart(options.workflowId),
230
+ sanitizeMermaidIdPart(options.versionId),
231
+ sourceHash,
232
+ ].join(":");
233
+ };
234
+
235
+ export const buildMermaidRenderId = (
236
+ prefix: string,
237
+ cacheKey: string,
238
+ ): string =>
239
+ `${sanitizeMermaidIdPart(prefix)}-${sanitizeMermaidIdPart(cacheKey)}`;
240
+
241
+ export const makeMermaidSvgTransparent = (svg: string): string => {
242
+ const svgWithTransparentRoot = svg.replace(
243
+ /<svg\b([^>]*)>/i,
244
+ (match, attributes: string) => {
245
+ const styleMatch = attributes.match(/\sstyle="([^"]*)"/i);
246
+ if (!styleMatch) {
247
+ return `<svg${attributes} style="background-color: transparent;">`;
248
+ }
249
+
250
+ const cleanedStyle = styleMatch[1]
251
+ .split(";")
252
+ .map((entry) => entry.trim())
253
+ .filter(Boolean)
254
+ .filter(
255
+ (entry) =>
256
+ !entry.toLowerCase().startsWith("background-color") &&
257
+ !entry.toLowerCase().startsWith("background"),
258
+ )
259
+ .join("; ");
260
+ const nextStyle = ` style="background-color: transparent${cleanedStyle ? `; ${cleanedStyle}` : ""};"`;
261
+
262
+ return match.replace(styleMatch[0], nextStyle);
263
+ },
264
+ );
265
+
266
+ return svgWithTransparentRoot
267
+ .replace(
268
+ /<rect\b([^>]*\bclass="[^"]*\b(background|canvas)\b[^"]*"[^>]*)\/?>/gi,
269
+ "",
270
+ )
271
+ .replace(
272
+ /<rect\b([^>]*\bid="[^"]*(background|canvas)[^"]*"[^>]*)\/?>/gi,
273
+ "",
274
+ );
275
+ };
276
+
277
+ export const renderMermaidSvg = async ({
278
+ source,
279
+ cacheKey,
280
+ renderId,
281
+ transformSvg,
282
+ }: MermaidRenderOptions): Promise<string> => {
283
+ const normalizedSource = source.trim();
284
+ if (!normalizedSource) {
285
+ throw new Error("Mermaid source is empty.");
286
+ }
287
+
288
+ const cachedSvg = getCachedSvg(cacheKey);
289
+ if (cachedSvg) {
290
+ return cachedSvg;
291
+ }
292
+
293
+ const existingRequest = inFlightRenders.get(cacheKey);
294
+ if (existingRequest) {
295
+ return existingRequest;
296
+ }
297
+
298
+ const request = (async () => {
299
+ await acquireRenderSlot();
300
+ try {
301
+ const cachedBeforeRender = getCachedSvg(cacheKey);
302
+ if (cachedBeforeRender) {
303
+ return cachedBeforeRender;
304
+ }
305
+
306
+ ensureMermaidInitialized();
307
+ const result = await mermaid.render(renderId, normalizedSource);
308
+ const nextSvg = transformSvg ? transformSvg(result.svg) : result.svg;
309
+ storeCachedSvg(cacheKey, nextSvg);
310
+ return nextSvg;
311
+ } finally {
312
+ releaseRenderSlot();
313
+ }
314
+ })().finally(() => {
315
+ inFlightRenders.delete(cacheKey);
316
+ });
317
+
318
+ inFlightRenders.set(cacheKey, request);
319
+ return request;
320
+ };
321
+
322
+ export const __resetMermaidRenderCacheForTests = () => {
323
+ inFlightRenders.clear();
324
+ memoryCache.clear();
325
+ sessionCache.clear();
326
+ renderQueue.length = 0;
327
+ mermaidInitialized = false;
328
+ hydratedSessionCache = false;
329
+ activeRenders = 0;
330
+
331
+ if (isSessionStorageAvailable()) {
332
+ window.sessionStorage.removeItem(SESSION_STORAGE_KEY);
333
+ }
334
+ };