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.
- package/.bumpversion.cfg +14 -0
- package/.eslintrc +1 -0
- package/CHANGELOG.md +32 -0
- package/README.md +60 -0
- package/bin/orcheo-studio.js +39 -0
- package/components.json +21 -0
- package/dist/assets/arc-BbeTokFd.js +1 -0
- package/dist/assets/architectureDiagram-VXUJARFQ-CN00R9LC.js +36 -0
- package/dist/assets/avatar-01-CIAd4XAq.svg +1 -0
- package/dist/assets/avatar-02-BkgLJWQZ.svg +1 -0
- package/dist/assets/avatar-03-DVVcnD3b.svg +1 -0
- package/dist/assets/avatar-04-ydqFTDdh.svg +1 -0
- package/dist/assets/avatar-05-CSIhgJow.svg +1 -0
- package/dist/assets/avatar-06-B-h1Nz9Y.svg +1 -0
- package/dist/assets/avatar-07-BgkDZuBW.svg +1 -0
- package/dist/assets/avatar-08-C5KZjVH6.svg +1 -0
- package/dist/assets/avatar-09-2EGeSlPh.svg +1 -0
- package/dist/assets/avatar-10-DRf4ZGD2.svg +1 -0
- package/dist/assets/avatar-11-CEzBCpib.svg +1 -0
- package/dist/assets/avatar-12-COVngNEy.svg +1 -0
- package/dist/assets/avatar-13-D1i1tZVO.svg +1 -0
- package/dist/assets/avatar-14-B68CNAEs.svg +1 -0
- package/dist/assets/avatar-15-B9NsRNUX.svg +1 -0
- package/dist/assets/avatar-16-DQ_JJRGR.svg +1 -0
- package/dist/assets/avatar-17-DfDJkGv5.svg +1 -0
- package/dist/assets/avatar-18-BuxiqOaJ.svg +1 -0
- package/dist/assets/avatar-19-C2mJfrwW.svg +1 -0
- package/dist/assets/avatar-20-DPE_yE1a.svg +1 -0
- package/dist/assets/avatar-21-DbB0Lj6t.svg +1 -0
- package/dist/assets/blockDiagram-VD42YOAC-BPpieIRz.js +122 -0
- package/dist/assets/c4Diagram-YG6GDRKO-DAhuY1fj.js +10 -0
- package/dist/assets/channel-DtVQHWfl.js +1 -0
- package/dist/assets/chunk-4BX2VUAB-7RJQCroR.js +1 -0
- package/dist/assets/chunk-55IACEB6-CEN5yOA_.js +1 -0
- package/dist/assets/chunk-B4BG7PRW-vdlAz_3Q.js +165 -0
- package/dist/assets/chunk-DI55MBZ5-BTmKjGVg.js +220 -0
- package/dist/assets/chunk-FMBD7UC4-CwWvFfrg.js +15 -0
- package/dist/assets/chunk-QN33PNHL-XH90lUUN.js +1 -0
- package/dist/assets/chunk-QZHKN3VN-DMoMVES0.js +1 -0
- package/dist/assets/chunk-TZMSLE5B-Bx2XTXDY.js +1 -0
- package/dist/assets/classDiagram-2ON5EDUG-pw6P8q-u.js +1 -0
- package/dist/assets/classDiagram-v2-WZHVMYZB-pw6P8q-u.js +1 -0
- package/dist/assets/clone-DJq6GzHg.js +1 -0
- package/dist/assets/cose-bilkent-S5V4N54A-DS1MNwZB.js +1 -0
- package/dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
- package/dist/assets/dagre-6UL2VRFP-DdklXSXB.js +4 -0
- package/dist/assets/defaultLocale-C4B-KCzX.js +1 -0
- package/dist/assets/diagram-PSM6KHXK-BKBo8pqg.js +24 -0
- package/dist/assets/diagram-QEK2KX5R-DaavZhFO.js +43 -0
- package/dist/assets/diagram-S2PKOQOG-DkTwknYd.js +24 -0
- package/dist/assets/erDiagram-Q2GNP2WA-ClR5qEsI.js +60 -0
- package/dist/assets/flowDiagram-NV44I4VS-Cxt_sJHB.js +162 -0
- package/dist/assets/ganttDiagram-JELNMOA3-CIbs3JPJ.js +267 -0
- package/dist/assets/gitGraphDiagram-V2S2FVAM-DmqLh_uo.js +65 -0
- package/dist/assets/graph-zo28rS-a.js +1 -0
- package/dist/assets/index-B0_h2wCA.css +1 -0
- package/dist/assets/index-Be29_rJf.js +775 -0
- package/dist/assets/infoDiagram-HS3SLOUP-D9_rMkAf.js +2 -0
- package/dist/assets/init-Gi6I4Gst.js +1 -0
- package/dist/assets/isUndefined-C59bc74c.js +1 -0
- package/dist/assets/journeyDiagram-XKPGCS4Q-4ZuggLXE.js +139 -0
- package/dist/assets/kanban-definition-3W4ZIXB7-BQDNrhHL.js +89 -0
- package/dist/assets/katex-CBSAILhF.js +261 -0
- package/dist/assets/layout-CXbNm-Yo.js +1 -0
- package/dist/assets/linear-DQWATg1F.js +1 -0
- package/dist/assets/min-DJjRzMm8.js +1 -0
- package/dist/assets/mindmap-definition-VGOIOE7T-DiZQmsHT.js +68 -0
- package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/assets/pieDiagram-ADFJNKIX-Bkju7jCD.js +30 -0
- package/dist/assets/quadrantDiagram-AYHSOK5B-CIB47UvU.js +7 -0
- package/dist/assets/requirementDiagram-UZGBJVZJ-BSB3uACk.js +64 -0
- package/dist/assets/sankeyDiagram-TZEHDZUN-rB8wD2kd.js +10 -0
- package/dist/assets/sequenceDiagram-WL72ISMW-Cd9s3Q_1.js +145 -0
- package/dist/assets/stateDiagram-FKZM4ZOC-zAxtjcM9.js +1 -0
- package/dist/assets/stateDiagram-v2-4FDKWEC3-C4DctH65.js +1 -0
- package/dist/assets/timeline-definition-IT6M3QCI-Et89F1F3.js +61 -0
- package/dist/assets/treemap-GDKQZRPO-6mZVX2Gv.js +162 -0
- package/dist/assets/xychartDiagram-PRI3JC2R-CgyY8dNz.js +7 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.html +19 -0
- package/dist/robots.txt +2 -0
- package/eslint.config.js +49 -0
- package/index.html +18 -0
- package/package.json +183 -0
- package/postcss.config.js +6 -0
- package/public/favicon.ico +0 -0
- package/public/robots.txt +2 -0
- package/src/App.tsx +115 -0
- package/src/assets/avatars/avatar-01.svg +1 -0
- package/src/assets/avatars/avatar-02.svg +1 -0
- package/src/assets/avatars/avatar-03.svg +1 -0
- package/src/assets/avatars/avatar-04.svg +1 -0
- package/src/assets/avatars/avatar-05.svg +1 -0
- package/src/assets/avatars/avatar-06.svg +1 -0
- package/src/assets/avatars/avatar-07.svg +1 -0
- package/src/assets/avatars/avatar-08.svg +1 -0
- package/src/assets/avatars/avatar-09.svg +1 -0
- package/src/assets/avatars/avatar-10.svg +1 -0
- package/src/assets/avatars/avatar-11.svg +1 -0
- package/src/assets/avatars/avatar-12.svg +1 -0
- package/src/assets/avatars/avatar-13.svg +1 -0
- package/src/assets/avatars/avatar-14.svg +1 -0
- package/src/assets/avatars/avatar-15.svg +1 -0
- package/src/assets/avatars/avatar-16.svg +1 -0
- package/src/assets/avatars/avatar-17.svg +1 -0
- package/src/assets/avatars/avatar-18.svg +1 -0
- package/src/assets/avatars/avatar-19.svg +1 -0
- package/src/assets/avatars/avatar-20.svg +1 -0
- package/src/assets/avatars/avatar-21.svg +1 -0
- package/src/assets/avatars/index.ts +99 -0
- package/src/design-system/ui/alert-dialog.tsx +141 -0
- package/src/design-system/ui/alert.tsx +59 -0
- package/src/design-system/ui/avatar.tsx +51 -0
- package/src/design-system/ui/badge.tsx +38 -0
- package/src/design-system/ui/button.tsx +59 -0
- package/src/design-system/ui/card.tsx +83 -0
- package/src/design-system/ui/dialog.tsx +122 -0
- package/src/design-system/ui/dropdown-menu.tsx +201 -0
- package/src/design-system/ui/input.tsx +22 -0
- package/src/design-system/ui/label.tsx +26 -0
- package/src/design-system/ui/scroll-area.tsx +48 -0
- package/src/design-system/ui/select.tsx +159 -0
- package/src/design-system/ui/separator.tsx +31 -0
- package/src/design-system/ui/sheet.tsx +141 -0
- package/src/design-system/ui/skeleton.tsx +15 -0
- package/src/design-system/ui/switch.tsx +29 -0
- package/src/design-system/ui/table.tsx +120 -0
- package/src/design-system/ui/tabs.tsx +55 -0
- package/src/design-system/ui/textarea.tsx +22 -0
- package/src/design-system/ui/toast.tsx +132 -0
- package/src/design-system/ui/toaster.tsx +35 -0
- package/src/design-system/ui/toggle-group.tsx +61 -0
- package/src/design-system/ui/toggle.tsx +46 -0
- package/src/design-system/ui/tooltip.tsx +32 -0
- package/src/features/MODULES.md +199 -0
- package/src/features/account/components/settings/appearance-settings-tab.tsx +24 -0
- package/src/features/account/components/theme-settings.tsx +70 -0
- package/src/features/account/components/use-theme-preferences.ts +106 -0
- package/src/features/account/pages/profile/components/profile-general-tab.tsx +89 -0
- package/src/features/account/pages/profile/types.ts +7 -0
- package/src/features/account/pages/profile.tsx +71 -0
- package/src/features/account/pages/service-tokens.tsx +522 -0
- package/src/features/account/pages/settings.tsx +42 -0
- package/src/features/account/pages/workspace-management.tsx +63 -0
- package/src/features/account/pages/workspace-members.tsx +335 -0
- package/src/features/auth/components/auto-login.tsx +51 -0
- package/src/features/auth/components/require-auth.tsx +56 -0
- package/src/features/auth/lib/auth-session.ts +448 -0
- package/src/features/auth/lib/oidc-client.ts +565 -0
- package/src/features/auth/pages/login.tsx +24 -0
- package/src/features/auth/pages/oauth-callback.tsx +63 -0
- package/src/features/chatkit/components/chatkit-surface.tsx +60 -0
- package/src/features/chatkit/components/public-chat-config.ts +70 -0
- package/src/features/chatkit/components/public-chat-error-boundary.tsx +74 -0
- package/src/features/chatkit/components/public-chat-widget.tsx +150 -0
- package/src/features/chatkit/components/studio-chat-bubble.tsx +451 -0
- package/src/features/chatkit/lib/chatkit-attachments.ts +31 -0
- package/src/features/chatkit/lib/chatkit-client.ts +195 -0
- package/src/features/chatkit/lib/chatkit-theme.ts +20 -0
- package/src/features/chatkit/lib/telemetry.ts +29 -0
- package/src/features/chatkit/lib/workflow-session.ts +70 -0
- package/src/features/chatkit/pages/public-chat.tsx +445 -0
- package/src/features/shared/components/chat-interface-options.ts +325 -0
- package/src/features/shared/components/chat-interface.types.ts +47 -0
- package/src/features/shared/components/top-navigation/account-menu.tsx +172 -0
- package/src/features/shared/components/top-navigation/active-workspace-indicator.tsx +280 -0
- package/src/features/shared/components/top-navigation/studio-brand.tsx +59 -0
- package/src/features/shared/components/top-navigation/top-navigation-types.ts +22 -0
- package/src/features/shared/components/top-navigation/version-status.tsx +280 -0
- package/src/features/shared/components/top-navigation.tsx +42 -0
- package/src/features/shared/components/workspace-bootstrap-gate.tsx +235 -0
- package/src/features/workflow/components/dialogs/add-credential-dialog.tsx +245 -0
- package/src/features/workflow/components/dialogs/confirm-delete-workflow-dialog.tsx +52 -0
- package/src/features/workflow/components/dialogs/credential-access-badge.tsx +34 -0
- package/src/features/workflow/components/dialogs/credential-status-badge.tsx +45 -0
- package/src/features/workflow/components/dialogs/credentials-table.tsx +453 -0
- package/src/features/workflow/components/dialogs/credentials-vault.tsx +85 -0
- package/src/features/workflow/components/dialogs/edit-credential-dialog.tsx +264 -0
- package/src/features/workflow/components/dialogs/update-workflow-dialog.tsx +214 -0
- package/src/features/workflow/components/dialogs/upload-workflow-dialog.tsx +288 -0
- package/src/features/workflow/components/forms/schema-config-form.tsx +41 -0
- package/src/features/workflow/components/layouts/sidebar-layout.tsx +288 -0
- package/src/features/workflow/components/layouts/use-sidebar-resize.ts +164 -0
- package/src/features/workflow/components/layouts/workflow-page-layout.tsx +69 -0
- package/src/features/workflow/components/panels/json-object-field.tsx +138 -0
- package/src/features/workflow/components/panels/rjsf-basic-widgets.tsx +21 -0
- package/src/features/workflow/components/panels/rjsf-input-widgets.tsx +105 -0
- package/src/features/workflow/components/panels/rjsf-templates.tsx +147 -0
- package/src/features/workflow/components/panels/rjsf-text-widgets.tsx +139 -0
- package/src/features/workflow/components/panels/rjsf-theme.tsx +10 -0
- package/src/features/workflow/components/panels/schema-dnd.ts +79 -0
- package/src/features/workflow/components/panels/workflow-diff-dialog.tsx +207 -0
- package/src/features/workflow/components/panels/workflow-history-filters.tsx +62 -0
- package/src/features/workflow/components/panels/workflow-history-footer.tsx +28 -0
- package/src/features/workflow/components/panels/workflow-history-header.tsx +47 -0
- package/src/features/workflow/components/panels/workflow-history-table.tsx +148 -0
- package/src/features/workflow/components/panels/workflow-history.tsx +150 -0
- package/src/features/workflow/components/panels/workflow-tabs.tsx +29 -0
- package/src/features/workflow/components/trace/agent-prism/Avatar.tsx +146 -0
- package/src/features/workflow/components/trace/agent-prism/Badge.tsx +95 -0
- package/src/features/workflow/components/trace/agent-prism/BrandLogo.tsx +102 -0
- package/src/features/workflow/components/trace/agent-prism/Button.tsx +124 -0
- package/src/features/workflow/components/trace/agent-prism/CollapseAndExpandControls.tsx +45 -0
- package/src/features/workflow/components/trace/agent-prism/CollapsibleSection.tsx +124 -0
- package/src/features/workflow/components/trace/agent-prism/CopyButton.tsx +63 -0
- package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsView.tsx +146 -0
- package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewAttributesTab.tsx +125 -0
- package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewContentViewer.tsx +51 -0
- package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewHeader.tsx +100 -0
- package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewInputOutputTab.tsx +401 -0
- package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewJsonOutput.tsx +33 -0
- package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewRawDataTab.tsx +27 -0
- package/src/features/workflow/components/trace/agent-prism/IconButton.tsx +75 -0
- package/src/features/workflow/components/trace/agent-prism/PriceBadge.tsx +14 -0
- package/src/features/workflow/components/trace/agent-prism/SearchInput.tsx +17 -0
- package/src/features/workflow/components/trace/agent-prism/SpanBadge.tsx +54 -0
- package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCard.tsx +480 -0
- package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardBadges.tsx +23 -0
- package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardConnector.tsx +36 -0
- package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardTimeline.tsx +60 -0
- package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardToggle.tsx +39 -0
- package/src/features/workflow/components/trace/agent-prism/SpanStatus.tsx +80 -0
- package/src/features/workflow/components/trace/agent-prism/TabSelector.tsx +35 -0
- package/src/features/workflow/components/trace/agent-prism/Tabs.tsx +140 -0
- package/src/features/workflow/components/trace/agent-prism/TextInput.tsx +143 -0
- package/src/features/workflow/components/trace/agent-prism/TimestampBadge.tsx +22 -0
- package/src/features/workflow/components/trace/agent-prism/TokensBadge.tsx +27 -0
- package/src/features/workflow/components/trace/agent-prism/TraceList/TraceList.tsx +123 -0
- package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItem.tsx +86 -0
- package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItemHeader.tsx +37 -0
- package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewer.tsx +208 -0
- package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerDesktopLayout.tsx +99 -0
- package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerMobileLayout.tsx +103 -0
- package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerPlaceholder.tsx +5 -0
- package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerSearchAndControls.tsx +30 -0
- package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerTreeViewContainer.tsx +76 -0
- package/src/features/workflow/components/trace/agent-prism/TraceViewer/useTraceSelection.ts +186 -0
- package/src/features/workflow/components/trace/agent-prism/TreeView.tsx +73 -0
- package/src/features/workflow/components/trace/agent-prism/index.ts +7 -0
- package/src/features/workflow/components/trace/agent-prism/shared.ts +170 -0
- package/src/features/workflow/components/trace/agent-prism/theme/index.ts +101 -0
- package/src/features/workflow/components/trace/agent-prism/theme/theme.css +247 -0
- package/src/features/workflow/data/templates/assets/vibe-agent/config.json +5 -0
- package/src/features/workflow/data/templates/candidate-badges.ts +138 -0
- package/src/features/workflow/data/templates/index.ts +29 -0
- package/src/features/workflow/data/templates/template-definition.ts +77 -0
- package/src/features/workflow/data/templates/template-owner.ts +7 -0
- package/src/features/workflow/data/workflow-data.ts +8 -0
- package/src/features/workflow/data/workflow-types.ts +57 -0
- package/src/features/workflow/lib/mermaid-renderer.ts +334 -0
- package/src/features/workflow/lib/workflow-diff.ts +191 -0
- package/src/features/workflow/lib/workflow-execution-builders.ts +103 -0
- package/src/features/workflow/lib/workflow-execution-formatters.ts +145 -0
- package/src/features/workflow/lib/workflow-execution-storage.ts +63 -0
- package/src/features/workflow/lib/workflow-execution.types.ts +80 -0
- package/src/features/workflow/lib/workflow-storage-api.ts +581 -0
- package/src/features/workflow/lib/workflow-storage-helpers.ts +373 -0
- package/src/features/workflow/lib/workflow-storage-versioning.ts +127 -0
- package/src/features/workflow/lib/workflow-storage.constants.ts +21 -0
- package/src/features/workflow/lib/workflow-storage.ts +482 -0
- package/src/features/workflow/lib/workflow-storage.types.ts +261 -0
- package/src/features/workflow/pages/workflow/components/settings-tab-content.tsx +428 -0
- package/src/features/workflow/pages/workflow/components/trace-tab-content.tsx +183 -0
- package/src/features/workflow/pages/workflow/components/workflow-config-sheet.tsx +207 -0
- package/src/features/workflow/pages/workflow/components/workflow-config-sheet.utils.ts +275 -0
- package/src/features/workflow/pages/workflow/components/workflow-layout.tsx +143 -0
- package/src/features/workflow/pages/workflow/components/workflow-tab-content.tsx +766 -0
- package/src/features/workflow/pages/workflow/handlers/credentials.ts +338 -0
- package/src/features/workflow/pages/workflow/helpers/execution.ts +39 -0
- package/src/features/workflow/pages/workflow/helpers/trace.ts +838 -0
- package/src/features/workflow/pages/workflow/helpers/types.ts +28 -0
- package/src/features/workflow/pages/workflow/hooks/controller/build-layout-props.ts +171 -0
- package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-controller.ts +19 -0
- package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-core.ts +84 -0
- package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-execution-controller.ts +167 -0
- package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-lifecycle.ts +37 -0
- package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-resources.ts +57 -0
- package/src/features/workflow/pages/workflow/hooks/execution-log-helpers.ts +75 -0
- package/src/features/workflow/pages/workflow/hooks/execution-node-status.ts +46 -0
- package/src/features/workflow/pages/workflow/hooks/execution-record-updater.ts +119 -0
- package/src/features/workflow/pages/workflow/hooks/execution-record.ts +31 -0
- package/src/features/workflow/pages/workflow/hooks/execution-runtime-updates.ts +96 -0
- package/src/features/workflow/pages/workflow/hooks/use-execution-trace.ts +512 -0
- package/src/features/workflow/pages/workflow/hooks/use-execution-updates.ts +125 -0
- package/src/features/workflow/pages/workflow/hooks/use-pause-workflow.ts +70 -0
- package/src/features/workflow/pages/workflow/hooks/use-studio-ui-state.ts +10 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-chat.ts +212 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-credential-readiness.ts +72 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-credentials.ts +167 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-execution-state.ts +20 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-listeners.ts +182 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-loader.ts +236 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-metadata-state.ts +56 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-saver.ts +191 -0
- package/src/features/workflow/pages/workflow/hooks/use-workflow-storage-listener.ts +81 -0
- package/src/features/workflow/pages/workflow/hooks/workflow-runner-websocket.ts +150 -0
- package/src/features/workflow/pages/workflow-gallery/types.ts +3 -0
- package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-actions.ts +223 -0
- package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-state.ts +206 -0
- package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery.ts +14 -0
- package/src/features/workflow/pages/workflow-gallery/workflow-card-size.ts +8 -0
- package/src/features/workflow/pages/workflow-gallery/workflow-card.tsx +327 -0
- package/src/features/workflow/pages/workflow-gallery/workflow-gallery-tabs.tsx +173 -0
- package/src/features/workflow/pages/workflow-gallery.tsx +96 -0
- package/src/features/workflow/pages/workflow.tsx +119 -0
- package/src/features/workflow/types/credential-vault.ts +52 -0
- package/src/hooks/browser-context-provider.tsx +19 -0
- package/src/hooks/use-browser-context.ts +188 -0
- package/src/hooks/use-color-scheme.ts +77 -0
- package/src/hooks/use-credential-vault.ts +442 -0
- package/src/hooks/use-page-context.ts +39 -0
- package/src/hooks/use-toast.ts +182 -0
- package/src/hooks/use-uploads-allowed.ts +28 -0
- package/src/index.css +95 -0
- package/src/lib/api.ts +445 -0
- package/src/lib/auth-fetch.ts +35 -0
- package/src/lib/config.ts +102 -0
- package/src/lib/theme.ts +109 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/workspace-routing.ts +67 -0
- package/src/lib/workspace-session.ts +66 -0
- package/src/lib/workspace-slug.ts +10 -0
- package/src/main.tsx +28 -0
- package/src/vite-env.d.ts +17 -0
- package/tailwind.config.js +153 -0
- package/tsconfig.app.json +30 -0
- package/tsconfig.json +16 -0
- package/tsconfig.node.json +21 -0
- package/vite.config.ts +122 -0
package/src/index.css
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer base {
|
|
6
|
+
:root {
|
|
7
|
+
--background: 0 0% 100%;
|
|
8
|
+
--foreground: 240 10% 3.9%;
|
|
9
|
+
--card: 0 0% 100%;
|
|
10
|
+
--card-foreground: 240 10% 3.9%;
|
|
11
|
+
--popover: 0 0% 100%;
|
|
12
|
+
--popover-foreground: 240 10% 3.9%;
|
|
13
|
+
--primary: 240 5.9% 10%;
|
|
14
|
+
--primary-foreground: 0 0% 98%;
|
|
15
|
+
--secondary: 240 4.8% 95.9%;
|
|
16
|
+
--secondary-foreground: 240 5.9% 10%;
|
|
17
|
+
--muted: 240 4.8% 95.9%;
|
|
18
|
+
--muted-foreground: 240 3.8% 46.1%;
|
|
19
|
+
--accent: 240 4.8% 95.9%;
|
|
20
|
+
--accent-foreground: 240 5.9% 10%;
|
|
21
|
+
--destructive: 0 84.2% 60.2%;
|
|
22
|
+
--destructive-foreground: 0 0% 98%;
|
|
23
|
+
--border: 240 5.9% 90%;
|
|
24
|
+
--input: 240 5.9% 90%;
|
|
25
|
+
--ring: 240 5.9% 10%;
|
|
26
|
+
--radius: 0.5rem;
|
|
27
|
+
--chart-1: 12 76% 61%;
|
|
28
|
+
--chart-2: 173 58% 39%;
|
|
29
|
+
--chart-3: 197 37% 24%;
|
|
30
|
+
--chart-4: 43 74% 66%;
|
|
31
|
+
--chart-5: 27 87% 67%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.dark {
|
|
35
|
+
--background: 240 10% 3.9%;
|
|
36
|
+
--foreground: 0 0% 98%;
|
|
37
|
+
--card: 240 10% 3.9%;
|
|
38
|
+
--card-foreground: 0 0% 98%;
|
|
39
|
+
--popover: 240 10% 3.9%;
|
|
40
|
+
--popover-foreground: 0 0% 98%;
|
|
41
|
+
--primary: 0 0% 98%;
|
|
42
|
+
--primary-foreground: 240 5.9% 10%;
|
|
43
|
+
--secondary: 240 3.7% 15.9%;
|
|
44
|
+
--secondary-foreground: 0 0% 98%;
|
|
45
|
+
--muted: 240 3.7% 15.9%;
|
|
46
|
+
--muted-foreground: 240 5% 64.9%;
|
|
47
|
+
--accent: 240 3.7% 15.9%;
|
|
48
|
+
--accent-foreground: 0 0% 98%;
|
|
49
|
+
--destructive: 0 62.8% 30.6%;
|
|
50
|
+
--destructive-foreground: 0 0% 98%;
|
|
51
|
+
--border: 240 3.7% 15.9%;
|
|
52
|
+
--input: 240 3.7% 15.9%;
|
|
53
|
+
--ring: 240 4.9% 83.9%;
|
|
54
|
+
--chart-1: 220 70% 50%;
|
|
55
|
+
--chart-2: 160 60% 45%;
|
|
56
|
+
--chart-3: 30 80% 55%;
|
|
57
|
+
--chart-4: 280 65% 60%;
|
|
58
|
+
--chart-5: 340 75% 55%;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@layer base {
|
|
63
|
+
* {
|
|
64
|
+
@apply border-border;
|
|
65
|
+
}
|
|
66
|
+
body {
|
|
67
|
+
@apply bg-background text-foreground;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@layer components {
|
|
72
|
+
.react-flow__controls {
|
|
73
|
+
@apply flex flex-col overflow-hidden rounded-xl border border-slate-200/80 bg-white/95 text-slate-700 shadow-lg backdrop-blur-sm;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.react-flow__controls-button {
|
|
77
|
+
@apply flex h-10 w-10 items-center justify-center border-b border-slate-200/70 text-slate-700 transition-colors duration-200 hover:bg-slate-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-500/40 focus-visible:ring-offset-2 focus-visible:ring-offset-white;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.react-flow__controls-button:last-child {
|
|
81
|
+
@apply border-b-0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.react-flow__controls-button svg {
|
|
85
|
+
@apply text-current;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.dark .react-flow__controls {
|
|
89
|
+
@apply border-slate-800/80 bg-slate-900/90 text-slate-200 shadow-[0_18px_40px_rgba(0,0,0,0.65)];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.dark .react-flow__controls-button {
|
|
93
|
+
@apply border-slate-800/70 text-slate-400 hover:bg-slate-800 focus-visible:ring-slate-300/40 focus-visible:ring-offset-slate-900;
|
|
94
|
+
}
|
|
95
|
+
}
|
package/src/lib/api.ts
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import { authFetch } from "./auth-fetch";
|
|
2
|
+
import { buildBackendHttpUrl } from "./config";
|
|
3
|
+
|
|
4
|
+
export interface NodeExecutionRequest {
|
|
5
|
+
node_config: Record<string, unknown>;
|
|
6
|
+
inputs?: Record<string, unknown>;
|
|
7
|
+
workflow_id?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface NodeExecutionResponse {
|
|
11
|
+
status: "success" | "error";
|
|
12
|
+
result?: unknown;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface PackageVersionStatus {
|
|
17
|
+
package: string;
|
|
18
|
+
current_version: string | null;
|
|
19
|
+
latest_version: string | null;
|
|
20
|
+
minimum_recommended_version: string | null;
|
|
21
|
+
release_notes_url: string | null;
|
|
22
|
+
update_available: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SystemInfoResponse {
|
|
26
|
+
backend: PackageVersionStatus;
|
|
27
|
+
cli: PackageVersionStatus;
|
|
28
|
+
studio: PackageVersionStatus;
|
|
29
|
+
checked_at: string;
|
|
30
|
+
uploads_allowed: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ActiveWorkspaceResponse {
|
|
34
|
+
workspace_id?: string;
|
|
35
|
+
slug: string;
|
|
36
|
+
name: string;
|
|
37
|
+
role: "owner" | "admin" | "editor" | "viewer";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface WorkspaceMembershipSummary {
|
|
41
|
+
workspace_id: string;
|
|
42
|
+
slug: string;
|
|
43
|
+
name: string;
|
|
44
|
+
role: "owner" | "admin" | "editor" | "viewer";
|
|
45
|
+
status: "active" | "suspended" | "deleted";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface WorkspaceMembershipsResponse {
|
|
49
|
+
memberships: WorkspaceMembershipSummary[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface WorkspaceCreateRequest {
|
|
53
|
+
slug: string;
|
|
54
|
+
name: string;
|
|
55
|
+
owner_user_id?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface WorkspaceResponse {
|
|
59
|
+
id: string;
|
|
60
|
+
slug: string;
|
|
61
|
+
name: string;
|
|
62
|
+
status: "active" | "suspended" | "deleted";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface DevLoginRequest {
|
|
66
|
+
provider?: string;
|
|
67
|
+
email?: string;
|
|
68
|
+
name?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface DevLoginResponse {
|
|
72
|
+
provider: string;
|
|
73
|
+
subject: string;
|
|
74
|
+
display_name: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Execute a single node in isolation for testing/preview purposes.
|
|
79
|
+
*
|
|
80
|
+
* @param request - Node execution request containing node_config, inputs, and optional workflow_id
|
|
81
|
+
* @param baseUrl - Optional backend base URL (defaults to configured backend URL)
|
|
82
|
+
* @returns Promise resolving to the node execution response
|
|
83
|
+
* @throws Error if the request fails
|
|
84
|
+
*/
|
|
85
|
+
export async function executeNode(
|
|
86
|
+
request: NodeExecutionRequest,
|
|
87
|
+
baseUrl?: string,
|
|
88
|
+
): Promise<NodeExecutionResponse> {
|
|
89
|
+
const url = buildBackendHttpUrl("/api/nodes/execute", baseUrl);
|
|
90
|
+
|
|
91
|
+
const response = await authFetch(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: {
|
|
94
|
+
"Content-Type": "application/json",
|
|
95
|
+
},
|
|
96
|
+
body: JSON.stringify(request),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
const errorData = await response.json().catch(() => ({
|
|
101
|
+
detail: "Failed to execute node",
|
|
102
|
+
}));
|
|
103
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return response.json();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function getSystemInfo(
|
|
110
|
+
baseUrl?: string,
|
|
111
|
+
): Promise<SystemInfoResponse> {
|
|
112
|
+
const url = buildBackendHttpUrl("/api/system/info", baseUrl);
|
|
113
|
+
const response = await authFetch(url, {
|
|
114
|
+
method: "GET",
|
|
115
|
+
headers: {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
const errorData = await response.json().catch(() => ({
|
|
122
|
+
detail: "Failed to fetch system info",
|
|
123
|
+
}));
|
|
124
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return response.json();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function getActiveWorkspace(
|
|
131
|
+
baseUrl?: string,
|
|
132
|
+
): Promise<ActiveWorkspaceResponse> {
|
|
133
|
+
const url = buildBackendHttpUrl("/api/workspaces/active", baseUrl);
|
|
134
|
+
const response = await authFetch(url, {
|
|
135
|
+
method: "GET",
|
|
136
|
+
headers: {
|
|
137
|
+
"Content-Type": "application/json",
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
const errorData = await response.json().catch(() => ({
|
|
143
|
+
detail: "Failed to fetch active workspace",
|
|
144
|
+
}));
|
|
145
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return response.json();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function getMyWorkspaces(
|
|
152
|
+
baseUrl?: string,
|
|
153
|
+
): Promise<WorkspaceMembershipsResponse> {
|
|
154
|
+
const url = buildBackendHttpUrl("/api/workspaces/me", baseUrl);
|
|
155
|
+
const response = await authFetch(url, {
|
|
156
|
+
method: "GET",
|
|
157
|
+
headers: {
|
|
158
|
+
"Content-Type": "application/json",
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
const errorData = await response.json().catch(() => ({
|
|
164
|
+
detail: "Failed to fetch workspaces",
|
|
165
|
+
}));
|
|
166
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return response.json();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function startDevLogin(
|
|
173
|
+
request: DevLoginRequest,
|
|
174
|
+
baseUrl?: string,
|
|
175
|
+
): Promise<DevLoginResponse> {
|
|
176
|
+
const url = buildBackendHttpUrl("/api/auth/dev/login", baseUrl);
|
|
177
|
+
const response = await authFetch(url, {
|
|
178
|
+
method: "POST",
|
|
179
|
+
headers: {
|
|
180
|
+
"Content-Type": "application/json",
|
|
181
|
+
},
|
|
182
|
+
body: JSON.stringify(request),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
if (!response.ok) {
|
|
186
|
+
const errorData = await response.json().catch(() => ({
|
|
187
|
+
detail: "Failed to start developer login",
|
|
188
|
+
}));
|
|
189
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return response.json();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function endDevLogin(baseUrl?: string): Promise<void> {
|
|
196
|
+
const url = buildBackendHttpUrl("/api/auth/dev/logout", baseUrl);
|
|
197
|
+
const response = await authFetch(url, {
|
|
198
|
+
method: "POST",
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (!response.ok && response.status !== 204) {
|
|
202
|
+
const errorData = await response.json().catch(() => ({
|
|
203
|
+
detail: "Failed to end developer login",
|
|
204
|
+
}));
|
|
205
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function createWorkspace(
|
|
210
|
+
request: WorkspaceCreateRequest,
|
|
211
|
+
baseUrl?: string,
|
|
212
|
+
): Promise<WorkspaceResponse> {
|
|
213
|
+
return requestSystemJson<WorkspaceResponse>(
|
|
214
|
+
"/api/workspaces",
|
|
215
|
+
{
|
|
216
|
+
method: "POST",
|
|
217
|
+
body: JSON.stringify(request),
|
|
218
|
+
},
|
|
219
|
+
baseUrl,
|
|
220
|
+
{ includeWorkspaceHeaders: false },
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function requestSystemJson<T>(
|
|
225
|
+
path: string,
|
|
226
|
+
init: RequestInit,
|
|
227
|
+
baseUrl?: string,
|
|
228
|
+
options: { includeWorkspaceHeaders?: boolean } = {},
|
|
229
|
+
): Promise<T> {
|
|
230
|
+
const url = buildBackendHttpUrl(path, baseUrl);
|
|
231
|
+
const response = await authFetch(
|
|
232
|
+
url,
|
|
233
|
+
{
|
|
234
|
+
...init,
|
|
235
|
+
headers: {
|
|
236
|
+
"Content-Type": "application/json",
|
|
237
|
+
...(init.headers ?? {}),
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
options,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (!response.ok) {
|
|
244
|
+
const errorData = await response.json().catch(() => ({
|
|
245
|
+
detail: "Failed to complete request",
|
|
246
|
+
}));
|
|
247
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return response.json();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface WorkspaceMember {
|
|
254
|
+
id: string;
|
|
255
|
+
workspace_id: string;
|
|
256
|
+
user_id: string;
|
|
257
|
+
user_name?: string;
|
|
258
|
+
role: "owner" | "admin" | "editor" | "viewer";
|
|
259
|
+
created_at: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export async function listWorkspaceMembers(
|
|
263
|
+
slug: string,
|
|
264
|
+
baseUrl?: string,
|
|
265
|
+
): Promise<WorkspaceMember[]> {
|
|
266
|
+
return requestSystemJson<WorkspaceMember[]>(
|
|
267
|
+
`/api/workspaces/${slug}/members`,
|
|
268
|
+
{ method: "GET" },
|
|
269
|
+
baseUrl,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export async function addWorkspaceMember(
|
|
274
|
+
slug: string,
|
|
275
|
+
request: { user_id: string; role: "owner" | "admin" | "editor" | "viewer" },
|
|
276
|
+
baseUrl?: string,
|
|
277
|
+
): Promise<WorkspaceMember> {
|
|
278
|
+
return requestSystemJson<WorkspaceMember>(
|
|
279
|
+
`/api/workspaces/${slug}/members`,
|
|
280
|
+
{ method: "POST", body: JSON.stringify(request) },
|
|
281
|
+
baseUrl,
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export async function updateWorkspaceMemberRole(
|
|
286
|
+
slug: string,
|
|
287
|
+
userId: string,
|
|
288
|
+
role: "owner" | "admin" | "editor" | "viewer",
|
|
289
|
+
baseUrl?: string,
|
|
290
|
+
): Promise<WorkspaceMember> {
|
|
291
|
+
return requestSystemJson<WorkspaceMember>(
|
|
292
|
+
`/api/workspaces/${slug}/members/${userId}`,
|
|
293
|
+
{ method: "PATCH", body: JSON.stringify({ role }) },
|
|
294
|
+
baseUrl,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export async function removeWorkspaceMember(
|
|
299
|
+
slug: string,
|
|
300
|
+
userId: string,
|
|
301
|
+
baseUrl?: string,
|
|
302
|
+
): Promise<void> {
|
|
303
|
+
const url = buildBackendHttpUrl(
|
|
304
|
+
`/api/workspaces/${slug}/members/${userId}`,
|
|
305
|
+
baseUrl,
|
|
306
|
+
);
|
|
307
|
+
const response = await authFetch(url, { method: "DELETE" });
|
|
308
|
+
|
|
309
|
+
if (!response.ok) {
|
|
310
|
+
const errorData = await response.json().catch(() => ({
|
|
311
|
+
detail: "Failed to remove workspace member",
|
|
312
|
+
}));
|
|
313
|
+
throw new Error(errorData.detail || `HTTP ${response.status}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export interface ServiceToken {
|
|
318
|
+
identifier: string;
|
|
319
|
+
secret?: string | null;
|
|
320
|
+
secret_preview?: string | null;
|
|
321
|
+
scopes: string[];
|
|
322
|
+
workspace_ids: string[];
|
|
323
|
+
issued_at: string | null;
|
|
324
|
+
expires_at: string | null;
|
|
325
|
+
last_used_at?: string | null;
|
|
326
|
+
use_count?: number | null;
|
|
327
|
+
revoked_at?: string | null;
|
|
328
|
+
revocation_reason?: string | null;
|
|
329
|
+
rotated_to?: string | null;
|
|
330
|
+
message?: string | null;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export interface ServiceTokenListResponse {
|
|
334
|
+
tokens: ServiceToken[];
|
|
335
|
+
total: number;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export interface CreateServiceTokenRequest {
|
|
339
|
+
identifier?: string;
|
|
340
|
+
scopes?: string[];
|
|
341
|
+
expires_in_seconds?: number | null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const extractErrorMessage = (data: unknown, fallback: string): string => {
|
|
345
|
+
if (!data || typeof data !== "object" || !("detail" in data)) {
|
|
346
|
+
return fallback;
|
|
347
|
+
}
|
|
348
|
+
const detail = (data as { detail: unknown }).detail;
|
|
349
|
+
if (typeof detail === "string") {
|
|
350
|
+
return detail;
|
|
351
|
+
}
|
|
352
|
+
if (detail && typeof detail === "object") {
|
|
353
|
+
const record = detail as Record<string, unknown>;
|
|
354
|
+
if (typeof record.message === "string") {
|
|
355
|
+
return record.message;
|
|
356
|
+
}
|
|
357
|
+
const nested = record.error;
|
|
358
|
+
if (
|
|
359
|
+
nested &&
|
|
360
|
+
typeof nested === "object" &&
|
|
361
|
+
typeof (nested as Record<string, unknown>).message === "string"
|
|
362
|
+
) {
|
|
363
|
+
return (nested as Record<string, string>).message;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return fallback;
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
async function serviceTokenRequest<T>(
|
|
370
|
+
path: string,
|
|
371
|
+
init: RequestInit,
|
|
372
|
+
fallbackError: string,
|
|
373
|
+
baseUrl?: string,
|
|
374
|
+
): Promise<T> {
|
|
375
|
+
const url = buildBackendHttpUrl(path, baseUrl);
|
|
376
|
+
const response = await authFetch(url, {
|
|
377
|
+
...init,
|
|
378
|
+
headers: {
|
|
379
|
+
"Content-Type": "application/json",
|
|
380
|
+
...(init.headers ?? {}),
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
if (!response.ok) {
|
|
385
|
+
const errorData = await response.json().catch(() => null);
|
|
386
|
+
throw new Error(extractErrorMessage(errorData, fallbackError));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (response.status === 204) {
|
|
390
|
+
return undefined as T;
|
|
391
|
+
}
|
|
392
|
+
return response.json();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export async function listServiceTokens(
|
|
396
|
+
baseUrl?: string,
|
|
397
|
+
): Promise<ServiceTokenListResponse> {
|
|
398
|
+
return serviceTokenRequest<ServiceTokenListResponse>(
|
|
399
|
+
"/api/admin/service-tokens",
|
|
400
|
+
{ method: "GET" },
|
|
401
|
+
"Failed to load service tokens",
|
|
402
|
+
baseUrl,
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export async function createServiceToken(
|
|
407
|
+
request: CreateServiceTokenRequest,
|
|
408
|
+
baseUrl?: string,
|
|
409
|
+
): Promise<ServiceToken> {
|
|
410
|
+
return serviceTokenRequest<ServiceToken>(
|
|
411
|
+
"/api/admin/service-tokens",
|
|
412
|
+
{ method: "POST", body: JSON.stringify(request) },
|
|
413
|
+
"Failed to create service token",
|
|
414
|
+
baseUrl,
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export async function rotateServiceToken(
|
|
419
|
+
tokenId: string,
|
|
420
|
+
overlapSeconds: number,
|
|
421
|
+
baseUrl?: string,
|
|
422
|
+
): Promise<ServiceToken> {
|
|
423
|
+
return serviceTokenRequest<ServiceToken>(
|
|
424
|
+
`/api/admin/service-tokens/${encodeURIComponent(tokenId)}/rotate`,
|
|
425
|
+
{
|
|
426
|
+
method: "POST",
|
|
427
|
+
body: JSON.stringify({ overlap_seconds: overlapSeconds }),
|
|
428
|
+
},
|
|
429
|
+
"Failed to rotate service token",
|
|
430
|
+
baseUrl,
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export async function revokeServiceToken(
|
|
435
|
+
tokenId: string,
|
|
436
|
+
reason: string,
|
|
437
|
+
baseUrl?: string,
|
|
438
|
+
): Promise<void> {
|
|
439
|
+
await serviceTokenRequest<void>(
|
|
440
|
+
`/api/admin/service-tokens/${encodeURIComponent(tokenId)}`,
|
|
441
|
+
{ method: "DELETE", body: JSON.stringify({ reason }) },
|
|
442
|
+
"Failed to revoke service token",
|
|
443
|
+
baseUrl,
|
|
444
|
+
);
|
|
445
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAccessToken,
|
|
3
|
+
getDevAuthSessionHeaderValue,
|
|
4
|
+
} from "@features/auth/lib/auth-session";
|
|
5
|
+
import { getWorkspaceSelectionHeaders } from "./workspace-session";
|
|
6
|
+
|
|
7
|
+
export const authFetch = async (
|
|
8
|
+
input: RequestInfo | URL,
|
|
9
|
+
init: RequestInit = {},
|
|
10
|
+
options: { includeWorkspaceHeaders?: boolean } = {},
|
|
11
|
+
): Promise<Response> => {
|
|
12
|
+
const headers = new Headers(init.headers ?? {});
|
|
13
|
+
const token = getAccessToken();
|
|
14
|
+
if (token && !headers.has("Authorization")) {
|
|
15
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
16
|
+
}
|
|
17
|
+
const devSession = getDevAuthSessionHeaderValue();
|
|
18
|
+
if (devSession && !headers.has("X-Orcheo-Dev-Session")) {
|
|
19
|
+
headers.set("X-Orcheo-Dev-Session", devSession);
|
|
20
|
+
}
|
|
21
|
+
if (options.includeWorkspaceHeaders ?? true) {
|
|
22
|
+
for (const [name, value] of Object.entries(
|
|
23
|
+
getWorkspaceSelectionHeaders(),
|
|
24
|
+
)) {
|
|
25
|
+
if (!headers.has(name)) {
|
|
26
|
+
headers.set(name, value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return globalThis.fetch(input, {
|
|
31
|
+
...init,
|
|
32
|
+
credentials: init.credentials ?? "include",
|
|
33
|
+
headers,
|
|
34
|
+
});
|
|
35
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const DEFAULT_BACKEND_URL = "http://localhost:2025";
|
|
2
|
+
|
|
3
|
+
const trimTrailingSlash = (value: string) => value.replace(/\/+$/, "");
|
|
4
|
+
|
|
5
|
+
const isPermittedProtocol = (protocol: string): boolean =>
|
|
6
|
+
["http:", "https:", "ws:", "wss:"].includes(protocol);
|
|
7
|
+
|
|
8
|
+
const isValidUrl = (value: string): boolean => {
|
|
9
|
+
if (!value.trim()) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const parsed = new URL(value);
|
|
14
|
+
return isPermittedProtocol(parsed.protocol);
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const normaliseBaseUrl = (value: string): string => {
|
|
21
|
+
if (!value) {
|
|
22
|
+
return DEFAULT_BACKEND_URL;
|
|
23
|
+
}
|
|
24
|
+
const trimmed = value.trim();
|
|
25
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
|
26
|
+
return trimTrailingSlash(trimmed);
|
|
27
|
+
}
|
|
28
|
+
if (trimmed.startsWith("ws://") || trimmed.startsWith("wss://")) {
|
|
29
|
+
return trimTrailingSlash(trimmed);
|
|
30
|
+
}
|
|
31
|
+
return trimTrailingSlash(`http://${trimmed}`);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const getBackendBaseUrl = (): string => {
|
|
35
|
+
const fromEnv = (import.meta.env?.VITE_ORCHEO_BACKEND_URL ?? "") as string;
|
|
36
|
+
const candidate = fromEnv || DEFAULT_BACKEND_URL;
|
|
37
|
+
const normalised = normaliseBaseUrl(candidate);
|
|
38
|
+
|
|
39
|
+
if (fromEnv && !isValidUrl(normalised)) {
|
|
40
|
+
console.warn(
|
|
41
|
+
"Invalid VITE_ORCHEO_BACKEND_URL provided, falling back to default backend URL.",
|
|
42
|
+
);
|
|
43
|
+
return normaliseBaseUrl(DEFAULT_BACKEND_URL);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return normalised;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const ensureHttpProtocol = (baseUrl: string): string => {
|
|
50
|
+
if (baseUrl.startsWith("http://") || baseUrl.startsWith("https://")) {
|
|
51
|
+
return baseUrl;
|
|
52
|
+
}
|
|
53
|
+
if (baseUrl.startsWith("ws://")) {
|
|
54
|
+
return `http://${baseUrl.slice(5)}`;
|
|
55
|
+
}
|
|
56
|
+
if (baseUrl.startsWith("wss://")) {
|
|
57
|
+
return `https://${baseUrl.slice(6)}`;
|
|
58
|
+
}
|
|
59
|
+
return `http://${baseUrl}`;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const buildBackendHttpUrl = (path: string, baseUrl?: string): string => {
|
|
63
|
+
const resolved = ensureHttpProtocol(baseUrl ?? getBackendBaseUrl());
|
|
64
|
+
const normalised = trimTrailingSlash(resolved);
|
|
65
|
+
const suffix = path.startsWith("/") ? path : `/${path}`;
|
|
66
|
+
return `${normalised}${suffix}`;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const getStudioVersion = (): string => __ORCHEO_STUDIO_VERSION__;
|
|
70
|
+
|
|
71
|
+
export const buildWorkflowWebSocketUrl = (
|
|
72
|
+
workflowId: string,
|
|
73
|
+
baseUrl?: string,
|
|
74
|
+
authToken?: string | null,
|
|
75
|
+
): string => {
|
|
76
|
+
const resolvedId = workflowId.trim();
|
|
77
|
+
if (!resolvedId) {
|
|
78
|
+
throw new Error("workflowId is required to create a WebSocket URL");
|
|
79
|
+
}
|
|
80
|
+
const resolved = normaliseBaseUrl(baseUrl ?? getBackendBaseUrl());
|
|
81
|
+
const search = authToken
|
|
82
|
+
? `?${new URLSearchParams({ access_token: authToken }).toString()}`
|
|
83
|
+
: "";
|
|
84
|
+
if (resolved.startsWith("ws://") || resolved.startsWith("wss://")) {
|
|
85
|
+
return `${trimTrailingSlash(resolved)}/ws/workflow/${resolvedId}${search}`;
|
|
86
|
+
}
|
|
87
|
+
const protocol = resolved.startsWith("https://") ? "wss://" : "ws://";
|
|
88
|
+
const host = resolved.replace(/^https?:\/\//, "").replace(/^ws?:\/\//, "");
|
|
89
|
+
return `${protocol}${trimTrailingSlash(host)}/ws/workflow/${resolvedId}${search}`;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const WEBSOCKET_AUTH_PROTOCOL = "orcheo-auth";
|
|
93
|
+
const WEBSOCKET_AUTH_PREFIX = "bearer.";
|
|
94
|
+
|
|
95
|
+
export const buildWorkflowWebSocketProtocols = (
|
|
96
|
+
token?: string | null,
|
|
97
|
+
): string[] | undefined => {
|
|
98
|
+
if (!token) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
return [WEBSOCKET_AUTH_PROTOCOL, `${WEBSOCKET_AUTH_PREFIX}${token}`];
|
|
102
|
+
};
|