@vertesia/ui 1.6.0-dev.20260918.090710Z → 1.6.0-dev.20260923.085325Z
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/lib/boot/branding.d.ts +13 -0
- package/lib/boot/branding.d.ts.map +1 -1
- package/lib/boot/branding.js +7 -0
- package/lib/boot/branding.js.map +1 -1
- package/lib/boot/index.d.ts +1 -1
- package/lib/boot/index.d.ts.map +1 -1
- package/lib/boot/index.js +5 -23
- package/lib/boot/index.js.map +1 -1
- package/lib/boot/loading.d.ts +4 -0
- package/lib/boot/loading.d.ts.map +1 -0
- package/lib/boot/loading.js +28 -0
- package/lib/boot/loading.js.map +1 -0
- package/lib/core/components/SelectList.d.ts.map +1 -1
- package/lib/core/components/SelectList.js +3 -3
- package/lib/core/components/SelectList.js.map +1 -1
- package/lib/core/components/SidePanel.d.ts.map +1 -1
- package/lib/core/components/SidePanel.js +2 -1
- package/lib/core/components/SidePanel.js.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeProvider.d.ts.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeProvider.js +21 -5
- package/lib/core/components/shadcn/theme/ThemeProvider.js.map +1 -1
- package/lib/env/index.d.ts +11 -0
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +16 -3
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +4 -1
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +5 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +9 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/magic-pdf/GroundedExtractionView.js +3 -3
- package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
- package/lib/features/media-viewer/AudioPanel.d.ts +10 -2
- package/lib/features/media-viewer/AudioPanel.d.ts.map +1 -1
- package/lib/features/media-viewer/AudioPanel.js +78 -13
- package/lib/features/media-viewer/AudioPanel.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts +2 -2
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.js +9 -7
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js +7 -3
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +4 -2
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
- package/lib/features/oauth/useMcpConnections.js +15 -9
- package/lib/features/oauth/useMcpConnections.js.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionContext.js +2 -0
- package/lib/features/store/objects/selection/ObjectsActionContext.js.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.d.ts +4 -2
- package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.js +6 -3
- package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.d.ts +4 -0
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.d.ts.map +1 -0
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.js +81 -0
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.js.map +1 -0
- package/lib/features/store/objects/selection/actions/index.d.ts +1 -0
- package/lib/features/store/objects/selection/actions/index.d.ts.map +1 -1
- package/lib/features/store/objects/selection/actions/index.js +1 -0
- package/lib/features/store/objects/selection/actions/index.js.map +1 -1
- package/lib/features/store/types/TypeRegistry.d.ts +345 -155
- package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +345 -155
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
- package/lib/i18n/locales/ar.json +10 -2
- package/lib/i18n/locales/de.json +6 -2
- package/lib/i18n/locales/en.json +6 -2
- package/lib/i18n/locales/es.json +6 -2
- package/lib/i18n/locales/fr.json +7 -2
- package/lib/i18n/locales/it.json +6 -2
- package/lib/i18n/locales/ja.json +6 -2
- package/lib/i18n/locales/ko.json +6 -2
- package/lib/i18n/locales/pt.json +6 -2
- package/lib/i18n/locales/ru.json +8 -2
- package/lib/i18n/locales/tr.json +6 -2
- package/lib/i18n/locales/zh-TW.json +6 -2
- package/lib/i18n/locales/zh.json +6 -2
- package/lib/session/UserSession.d.ts +3 -0
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +18 -8
- package/lib/session/UserSession.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +34 -24
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/authRoundTrip.d.ts +8 -0
- package/lib/session/auth/authRoundTrip.d.ts.map +1 -0
- package/lib/session/auth/authRoundTrip.js +22 -0
- package/lib/session/auth/authRoundTrip.js.map +1 -0
- package/lib/session/auth/composable.d.ts.map +1 -1
- package/lib/session/auth/composable.js +9 -7
- package/lib/session/auth/composable.js.map +1 -1
- package/lib/session/auth/domainRouting.d.ts +13 -6
- package/lib/session/auth/domainRouting.d.ts.map +1 -1
- package/lib/session/auth/domainRouting.js +2 -21
- package/lib/session/auth/domainRouting.js.map +1 -1
- package/lib/session/auth/oauth.d.ts +6 -1
- package/lib/session/auth/oauth.d.ts.map +1 -1
- package/lib/session/auth/oauth.js +145 -8
- package/lib/session/auth/oauth.js.map +1 -1
- package/lib/session/auth/tokenIssuer.d.ts +3 -0
- package/lib/session/auth/tokenIssuer.d.ts.map +1 -0
- package/lib/session/auth/tokenIssuer.js +27 -0
- package/lib/session/auth/tokenIssuer.js.map +1 -0
- package/lib/session/auth/vertesiaHosts.d.ts +47 -0
- package/lib/session/auth/vertesiaHosts.d.ts.map +1 -0
- package/lib/session/auth/vertesiaHosts.js +79 -0
- package/lib/session/auth/vertesiaHosts.js.map +1 -0
- package/lib/session/index.d.ts +1 -0
- package/lib/session/index.d.ts.map +1 -1
- package/lib/session/index.js +1 -0
- package/lib/session/index.js.map +1 -1
- package/lib/shell/AuthScreenPreview.d.ts +1 -1
- package/lib/shell/AuthScreenPreview.d.ts.map +1 -1
- package/lib/shell/AuthScreenPreview.js +2 -5
- package/lib/shell/AuthScreenPreview.js.map +1 -1
- package/lib/shell/BrandedAuthScreens.d.ts +1 -4
- package/lib/shell/BrandedAuthScreens.d.ts.map +1 -1
- package/lib/shell/BrandedAuthScreens.js +5 -26
- package/lib/shell/BrandedAuthScreens.js.map +1 -1
- package/lib/shell/BrandedLoadingIndicator.d.ts +11 -0
- package/lib/shell/BrandedLoadingIndicator.d.ts.map +1 -0
- package/lib/shell/BrandedLoadingIndicator.js +27 -0
- package/lib/shell/BrandedLoadingIndicator.js.map +1 -0
- package/lib/shell/SplashScreen.d.ts.map +1 -1
- package/lib/shell/SplashScreen.js +2 -1
- package/lib/shell/SplashScreen.js.map +1 -1
- package/lib/shell/apps/AppInstallationProvider.d.ts +16 -4
- package/lib/shell/apps/AppInstallationProvider.d.ts.map +1 -1
- package/lib/shell/apps/iframe-auth.d.ts +2 -0
- package/lib/shell/apps/iframe-auth.d.ts.map +1 -1
- package/lib/shell/apps/iframe-auth.js +6 -2
- package/lib/shell/apps/iframe-auth.js.map +1 -1
- package/lib/shell/index.d.ts +1 -0
- package/lib/shell/index.d.ts.map +1 -1
- package/lib/shell/index.js +1 -0
- package/lib/shell/index.js.map +1 -1
- package/lib/shell/login/SignInAuthPending.js +2 -2
- package/lib/shell/login/SignInAuthPending.js.map +1 -1
- package/lib/shell/login/SignInEmailStep.d.ts.map +1 -1
- package/lib/shell/login/SignInEmailStep.js +2 -2
- package/lib/shell/login/SignInEmailStep.js.map +1 -1
- package/lib/shell/login/TerminalLogin.d.ts.map +1 -1
- package/lib/shell/login/TerminalLogin.js +28 -21
- package/lib/shell/login/TerminalLogin.js.map +1 -1
- package/lib/vertesia-ui-boot.js +33 -29
- package/lib/vertesia-ui-boot.js.map +1 -1
- package/lib/vertesia-ui-core.js +34 -34
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-env.js +1 -1
- package/lib/vertesia-ui-env.js.map +1 -1
- package/lib/vertesia-ui-features.js +163 -163
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.Bl8KeZUK.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Bl8KeZUK.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BmT06XFI.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BmT06XFI.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Ch-Jjj0L.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Ch-Jjj0L.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CjhloW9s.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CjhloW9s.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CkfHdQzY.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CkfHdQzY.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DFuKfTe1.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DFuKfTe1.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DHqNVekZ.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DHqNVekZ.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DOaKbmaj.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DOaKbmaj.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Dge3Gl-h.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Dge3Gl-h.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.GLt-10Lx.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.GLt-10Lx.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.T-XtAGbw.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.T-XtAGbw.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.VOJyTpMM.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.VOJyTpMM.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.js +3 -3
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-layout.js +15 -15
- package/lib/vertesia-ui-layout.js.map +1 -1
- package/lib/vertesia-ui-rich-text.js +44 -44
- package/lib/vertesia-ui-rich-text.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +72 -48
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +51 -51
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/package.json +19 -19
- package/src/boot/branding.ts +8 -0
- package/src/boot/index.ts +6 -23
- package/src/boot/loading.ts +27 -0
- package/src/core/components/SelectList.tsx +5 -2
- package/src/core/components/SidePanel.tsx +65 -60
- package/src/core/components/shadcn/theme/ThemeProvider.test.tsx +101 -0
- package/src/core/components/shadcn/theme/ThemeProvider.tsx +21 -9
- package/src/env/index.test.ts +21 -0
- package/src/env/index.ts +33 -2
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +81 -0
- package/src/features/agent/chat/ModernAgentConversation.tsx +5 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +17 -1
- package/src/features/magic-pdf/GroundedExtractionView.tsx +3 -3
- package/src/features/media-viewer/AudioPanel.test.ts +84 -0
- package/src/features/media-viewer/AudioPanel.tsx +97 -14
- package/src/features/oauth/McpConnectionsButton.test.tsx +56 -0
- package/src/features/oauth/McpConnectionsButton.tsx +9 -6
- package/src/features/oauth/McpConnectionsDialog.tsx +14 -5
- package/src/features/oauth/useMcpConnections.test.ts +10 -0
- package/src/features/oauth/useMcpConnections.ts +18 -10
- package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -0
- package/src/features/store/objects/selection/SelectionActions.tsx +13 -6
- package/src/features/store/objects/selection/actions/StartWorkflowAction.tsx +162 -0
- package/src/features/store/objects/selection/actions/index.ts +1 -0
- package/src/i18n/locales/ar.json +10 -2
- package/src/i18n/locales/de.json +6 -2
- package/src/i18n/locales/en.json +6 -2
- package/src/i18n/locales/es.json +6 -2
- package/src/i18n/locales/fr.json +7 -2
- package/src/i18n/locales/it.json +6 -2
- package/src/i18n/locales/ja.json +6 -2
- package/src/i18n/locales/ko.json +6 -2
- package/src/i18n/locales/pt.json +6 -2
- package/src/i18n/locales/ru.json +8 -2
- package/src/i18n/locales/tr.json +6 -2
- package/src/i18n/locales/zh-TW.json +6 -2
- package/src/i18n/locales/zh.json +6 -2
- package/src/session/UserSession.test.ts +48 -3
- package/src/session/UserSession.ts +20 -8
- package/src/session/UserSessionProvider.handoff.test.tsx +103 -0
- package/src/session/UserSessionProvider.iframe.test.tsx +178 -0
- package/src/session/UserSessionProvider.state-mismatch.test.tsx +43 -0
- package/src/session/UserSessionProvider.tsx +35 -23
- package/src/session/auth/auth-flow.md +18 -5
- package/src/session/auth/authRoundTrip.ts +24 -0
- package/src/session/auth/composable.test.ts +23 -1
- package/src/session/auth/composable.ts +10 -8
- package/src/session/auth/domainRouting.ts +4 -25
- package/src/session/auth/oauth.test.ts +121 -4
- package/src/session/auth/oauth.ts +172 -11
- package/src/session/auth/tokenIssuer.test.ts +25 -0
- package/src/session/auth/tokenIssuer.ts +25 -0
- package/src/session/auth/vertesiaHosts.test.ts +26 -0
- package/src/session/auth/vertesiaHosts.ts +85 -0
- package/src/session/index.ts +1 -0
- package/src/shell/AuthScreenPreview.tsx +2 -6
- package/src/shell/BrandedAuthScreens.test.tsx +26 -0
- package/src/shell/BrandedAuthScreens.tsx +4 -40
- package/src/shell/BrandedLoadingIndicator.tsx +42 -0
- package/src/shell/SplashScreen.tsx +4 -4
- package/src/shell/apps/iframe-auth.test.ts +8 -11
- package/src/shell/apps/iframe-auth.ts +10 -1
- package/src/shell/index.tsx +1 -0
- package/src/shell/login/SignInAuthPending.tsx +2 -2
- package/src/shell/login/SignInEmailStep.tsx +4 -2
- package/src/shell/login/TerminalLogin.test.tsx +111 -0
- package/src/shell/login/TerminalLogin.tsx +61 -37
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts +0 -7
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts.map +0 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +0 -51
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +0 -1
- package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js.map +0 -1
- package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +0 -104
package/src/i18n/locales/ko.json
CHANGED
|
@@ -395,6 +395,7 @@
|
|
|
395
395
|
"mcpConnections.label": "MCP",
|
|
396
396
|
"mcpConnections.manage": "MCP 연결 관리",
|
|
397
397
|
"mcpConnections.managedByApp": "앱에서 관리",
|
|
398
|
+
"mcpConnections.noAuthentication": "인증 없음",
|
|
398
399
|
"mcpConnections.settings": "설정",
|
|
399
400
|
"mcpConnections.subtitle": "이 대화에서 사용할 수 있는 MCP 서버를 관리합니다.",
|
|
400
401
|
"mcpConnections.title": "MCP",
|
|
@@ -504,7 +505,7 @@
|
|
|
504
505
|
"store.actions.changeContentTypeDesc": "선택한 문서의 콘텐츠 유형 변경",
|
|
505
506
|
"store.actions.changeType": "유형 변경",
|
|
506
507
|
"store.actions.chooseExistingCollections": "기존 컬렉션에서 선택",
|
|
507
|
-
"store.actions.
|
|
508
|
+
"store.actions.chooseWorkflow": "시작할 워크플로를 선택하세요:",
|
|
508
509
|
"store.actions.confirmDeleteAll": "선택한 모든 객체를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
|
509
510
|
"store.actions.confirmDeleteSelected": "선택한 객체를 삭제하시겠습니까?\n이것은 컬렉션에서 제거하는 것이 아닙니다.",
|
|
510
511
|
"store.actions.confirmRemoveFromCollection": "선택한 객체를 이 컬렉션에서 제거하시겠습니까?",
|
|
@@ -521,15 +522,18 @@
|
|
|
521
522
|
"store.actions.exportProperties": "속성 내보내기",
|
|
522
523
|
"store.actions.noCollectionContext": "컬렉션 컨텍스트가 없습니다",
|
|
523
524
|
"store.actions.noObjectsSelected": "선택된 객체가 없습니다",
|
|
525
|
+
"store.actions.noWorkflowsAvailable": "사용 가능한 워크플로가 없습니다",
|
|
524
526
|
"store.actions.pleaseSelectObjectsToDelete": "삭제할 객체를 선택해 주세요",
|
|
525
527
|
"store.actions.pleaseSelectObjectsToRemove": "컬렉션에서 제거할 객체를 선택해 주세요",
|
|
526
528
|
"store.actions.removeFromCollection": "컬렉션에서 제거",
|
|
527
529
|
"store.actions.removeFromCollectionDesc": "이 컬렉션에서 선택한 객체 제거",
|
|
528
530
|
"store.actions.selectCollection": "컬렉션 선택",
|
|
531
|
+
"store.actions.start": "시작",
|
|
529
532
|
"store.actions.startWorkflow": "워크플로 시작",
|
|
530
|
-
"store.actions.startWorkflowByRule": "규칙으로 워크플로 시작",
|
|
531
533
|
"store.actions.startWorkflowDesc": "선택한 객체에 대해 워크플로 시작",
|
|
532
534
|
"store.actions.workflowStarted": "워크플로가 시작되었습니다",
|
|
535
|
+
"store.actions.workflowStartedOn_one": "{{count}}개 객체에 대해 {{name}}을(를) 시작했습니다",
|
|
536
|
+
"store.actions.workflowStartedOn_other": "{{count}}개 객체에 대해 {{name}}을(를) 시작했습니다",
|
|
533
537
|
"store.allowedContentTypes": "허용된 콘텐츠 유형",
|
|
534
538
|
"store.allowedContentTypesOptionalDescription": "컬렉션에 추가할 수 있는 콘텐츠 유형을 선택할 수 있습니다. 설정하지 않으면 모든 콘텐츠 유형이 허용됩니다.",
|
|
535
539
|
"store.allowedContentTypesSelectDescription": "컬렉션에 추가할 수 있는 콘텐츠 유형을 선택하세요. 설정하지 않으면 모든 콘텐츠 유형이 허용됩니다.",
|
package/src/i18n/locales/pt.json
CHANGED
|
@@ -397,6 +397,7 @@
|
|
|
397
397
|
"mcpConnections.label": "MCP",
|
|
398
398
|
"mcpConnections.manage": "Gerenciar conexões MCP",
|
|
399
399
|
"mcpConnections.managedByApp": "Gerenciado pelo aplicativo",
|
|
400
|
+
"mcpConnections.noAuthentication": "Sem autenticação",
|
|
400
401
|
"mcpConnections.settings": "Configurações",
|
|
401
402
|
"mcpConnections.subtitle": "Gerencie os servidores MCP disponíveis para esta conversa.",
|
|
402
403
|
"mcpConnections.title": "MCP",
|
|
@@ -507,7 +508,7 @@
|
|
|
507
508
|
"store.actions.changeContentTypeDesc": "Alterar o tipo de conteúdo dos documentos selecionados",
|
|
508
509
|
"store.actions.changeType": "Alterar tipo",
|
|
509
510
|
"store.actions.chooseExistingCollections": "Escolher de coleções existentes",
|
|
510
|
-
"store.actions.
|
|
511
|
+
"store.actions.chooseWorkflow": "Escolha um fluxo de trabalho para iniciar:",
|
|
511
512
|
"store.actions.confirmDeleteAll": "Tem certeza de que deseja excluir todos os objetos selecionados? Esta ação não pode ser desfeita.",
|
|
512
513
|
"store.actions.confirmDeleteSelected": "Tem certeza de que deseja excluir os objetos selecionados?\nIsso não os remove das coleções.",
|
|
513
514
|
"store.actions.confirmRemoveFromCollection": "Tem certeza de que deseja remover os objetos selecionados desta coleção?",
|
|
@@ -524,15 +525,18 @@
|
|
|
524
525
|
"store.actions.exportProperties": "Exportar propriedades",
|
|
525
526
|
"store.actions.noCollectionContext": "Sem contexto de coleção",
|
|
526
527
|
"store.actions.noObjectsSelected": "Nenhum objeto selecionado",
|
|
528
|
+
"store.actions.noWorkflowsAvailable": "Nenhum fluxo de trabalho disponível",
|
|
527
529
|
"store.actions.pleaseSelectObjectsToDelete": "Por favor, selecione objetos para excluir",
|
|
528
530
|
"store.actions.pleaseSelectObjectsToRemove": "Por favor, selecione objetos para remover da coleção",
|
|
529
531
|
"store.actions.removeFromCollection": "Remover da coleção",
|
|
530
532
|
"store.actions.removeFromCollectionDesc": "Remover os objetos selecionados desta coleção",
|
|
531
533
|
"store.actions.selectCollection": "Selecionar coleção",
|
|
534
|
+
"store.actions.start": "Iniciar",
|
|
532
535
|
"store.actions.startWorkflow": "Iniciar fluxo de trabalho",
|
|
533
|
-
"store.actions.startWorkflowByRule": "Iniciar um fluxo de trabalho por regra",
|
|
534
536
|
"store.actions.startWorkflowDesc": "Iniciar um fluxo de trabalho nos objetos selecionados",
|
|
535
537
|
"store.actions.workflowStarted": "Fluxo de trabalho iniciado",
|
|
538
|
+
"store.actions.workflowStartedOn_one": "{{name}} iniciado em {{count}} objeto",
|
|
539
|
+
"store.actions.workflowStartedOn_other": "{{name}} iniciado em {{count}} objetos",
|
|
536
540
|
"store.allowedContentTypes": "Tipos de conteúdo permitidos",
|
|
537
541
|
"store.allowedContentTypesOptionalDescription": "Opcionalmente selecione quais tipos de conteúdo podem ser adicionados à coleção. Se não definido, todos os tipos de conteúdo são permitidos.",
|
|
538
542
|
"store.allowedContentTypesSelectDescription": "Selecione quais tipos de conteúdo podem ser adicionados à coleção. Se não definido, todos os tipos de conteúdo são permitidos.",
|
package/src/i18n/locales/ru.json
CHANGED
|
@@ -401,6 +401,7 @@
|
|
|
401
401
|
"mcpConnections.label": "MCP",
|
|
402
402
|
"mcpConnections.manage": "Управление подключениями MCP",
|
|
403
403
|
"mcpConnections.managedByApp": "Управляется приложением",
|
|
404
|
+
"mcpConnections.noAuthentication": "Без аутентификации",
|
|
404
405
|
"mcpConnections.settings": "Настройки",
|
|
405
406
|
"mcpConnections.subtitle": "Управляйте серверами MCP, доступными для этого разговора.",
|
|
406
407
|
"mcpConnections.title": "MCP",
|
|
@@ -512,7 +513,7 @@
|
|
|
512
513
|
"store.actions.changeContentTypeDesc": "Изменить тип контента выбранных документов",
|
|
513
514
|
"store.actions.changeType": "Изменить тип",
|
|
514
515
|
"store.actions.chooseExistingCollections": "Выбрать из существующих коллекций",
|
|
515
|
-
"store.actions.
|
|
516
|
+
"store.actions.chooseWorkflow": "Выберите рабочий процесс для запуска:",
|
|
516
517
|
"store.actions.confirmDeleteAll": "Вы уверены, что хотите удалить все выбранные объекты? Это действие нельзя отменить.",
|
|
517
518
|
"store.actions.confirmDeleteSelected": "Вы уверены, что хотите удалить выбранные объекты?\nЭто не удаление из коллекций.",
|
|
518
519
|
"store.actions.confirmRemoveFromCollection": "Вы уверены, что хотите удалить выбранные объекты из этой коллекции?",
|
|
@@ -529,15 +530,20 @@
|
|
|
529
530
|
"store.actions.exportProperties": "Экспортировать свойства",
|
|
530
531
|
"store.actions.noCollectionContext": "Нет контекста коллекции",
|
|
531
532
|
"store.actions.noObjectsSelected": "Объекты не выбраны",
|
|
533
|
+
"store.actions.noWorkflowsAvailable": "Нет доступных рабочих процессов",
|
|
532
534
|
"store.actions.pleaseSelectObjectsToDelete": "Пожалуйста, выберите объекты для удаления",
|
|
533
535
|
"store.actions.pleaseSelectObjectsToRemove": "Пожалуйста, выберите объекты для удаления из коллекции",
|
|
534
536
|
"store.actions.removeFromCollection": "Удалить из коллекции",
|
|
535
537
|
"store.actions.removeFromCollectionDesc": "Удалить выбранные объекты из этой коллекции",
|
|
536
538
|
"store.actions.selectCollection": "Выбрать коллекцию",
|
|
539
|
+
"store.actions.start": "Запустить",
|
|
537
540
|
"store.actions.startWorkflow": "Запустить рабочий процесс",
|
|
538
|
-
"store.actions.startWorkflowByRule": "Запустить рабочий процесс по правилу",
|
|
539
541
|
"store.actions.startWorkflowDesc": "Запустить рабочий процесс для выбранных объектов",
|
|
540
542
|
"store.actions.workflowStarted": "Рабочий процесс запущен",
|
|
543
|
+
"store.actions.workflowStartedOn_few": "{{name}} запущен для {{count}} объектов",
|
|
544
|
+
"store.actions.workflowStartedOn_many": "{{name}} запущен для {{count}} объектов",
|
|
545
|
+
"store.actions.workflowStartedOn_one": "{{name}} запущен для {{count}} объекта",
|
|
546
|
+
"store.actions.workflowStartedOn_other": "{{name}} запущен для {{count}} объектов",
|
|
541
547
|
"store.allowedContentTypes": "Допустимые типы контента",
|
|
542
548
|
"store.allowedContentTypesOptionalDescription": "Дополнительно выберите, какие типы контента можно добавлять в коллекцию. Если не указано, допускаются все типы контента.",
|
|
543
549
|
"store.allowedContentTypesSelectDescription": "Выберите, какие типы контента можно добавлять в коллекцию. Если не указано, допускаются все типы контента.",
|
package/src/i18n/locales/tr.json
CHANGED
|
@@ -395,6 +395,7 @@
|
|
|
395
395
|
"mcpConnections.label": "MCP",
|
|
396
396
|
"mcpConnections.manage": "MCP bağlantılarını yönet",
|
|
397
397
|
"mcpConnections.managedByApp": "Uygulama tarafından yönetiliyor",
|
|
398
|
+
"mcpConnections.noAuthentication": "Kimlik doğrulama yok",
|
|
398
399
|
"mcpConnections.settings": "Ayarlar",
|
|
399
400
|
"mcpConnections.subtitle": "Bu konuşma için kullanılabilen MCP sunucularını yönetin.",
|
|
400
401
|
"mcpConnections.title": "MCP",
|
|
@@ -504,7 +505,7 @@
|
|
|
504
505
|
"store.actions.changeContentTypeDesc": "Seçili belgelerin İçerik Türünü değiştirin",
|
|
505
506
|
"store.actions.changeType": "Türü Değiştir",
|
|
506
507
|
"store.actions.chooseExistingCollections": "Mevcut koleksiyonlardan seçin",
|
|
507
|
-
"store.actions.
|
|
508
|
+
"store.actions.chooseWorkflow": "Başlatılacak bir iş akışı seçin:",
|
|
508
509
|
"store.actions.confirmDeleteAll": "Seçili tüm nesneleri silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
|
509
510
|
"store.actions.confirmDeleteSelected": "Seçili nesneleri silmek istediğinizden emin misiniz?\nBu, koleksiyonlardan kaldırma işlemi değildir.",
|
|
510
511
|
"store.actions.confirmRemoveFromCollection": "Seçili nesneleri bu koleksiyondan kaldırmak istediğinizden emin misiniz?",
|
|
@@ -521,15 +522,18 @@
|
|
|
521
522
|
"store.actions.exportProperties": "Özellikleri Dışa Aktar",
|
|
522
523
|
"store.actions.noCollectionContext": "Koleksiyon bağlamı yok",
|
|
523
524
|
"store.actions.noObjectsSelected": "Nesne seçilmedi",
|
|
525
|
+
"store.actions.noWorkflowsAvailable": "Kullanılabilir iş akışı yok",
|
|
524
526
|
"store.actions.pleaseSelectObjectsToDelete": "Lütfen silinecek nesneleri seçin",
|
|
525
527
|
"store.actions.pleaseSelectObjectsToRemove": "Lütfen koleksiyondan kaldırılacak nesneleri seçin",
|
|
526
528
|
"store.actions.removeFromCollection": "Koleksiyondan kaldır",
|
|
527
529
|
"store.actions.removeFromCollectionDesc": "Seçili nesneleri bu koleksiyondan kaldır",
|
|
528
530
|
"store.actions.selectCollection": "Koleksiyon Seçin",
|
|
531
|
+
"store.actions.start": "Başlat",
|
|
529
532
|
"store.actions.startWorkflow": "İş Akışı Başlat",
|
|
530
|
-
"store.actions.startWorkflowByRule": "Kurala Göre İş Akışı Başlat",
|
|
531
533
|
"store.actions.startWorkflowDesc": "Seçili nesneler üzerinde bir iş akışı başlat",
|
|
532
534
|
"store.actions.workflowStarted": "İş akışı başlatıldı",
|
|
535
|
+
"store.actions.workflowStartedOn_one": "{{count}} nesne üzerinde {{name}} başlatıldı",
|
|
536
|
+
"store.actions.workflowStartedOn_other": "{{count}} nesne üzerinde {{name}} başlatıldı",
|
|
533
537
|
"store.allowedContentTypes": "İzin Verilen İçerik Türleri",
|
|
534
538
|
"store.allowedContentTypesOptionalDescription": "İsteğe bağlı olarak koleksiyona eklenebilecek içerik türlerini seçin. Ayarlanmamışsa tüm içerik türlerine izin verilir.",
|
|
535
539
|
"store.allowedContentTypesSelectDescription": "Koleksiyona eklenebilecek içerik türlerini seçin. Ayarlanmamışsa tüm içerik türlerine izin verilir.",
|
|
@@ -395,6 +395,7 @@
|
|
|
395
395
|
"mcpConnections.label": "MCP",
|
|
396
396
|
"mcpConnections.manage": "管理 MCP 連線",
|
|
397
397
|
"mcpConnections.managedByApp": "由應用程式管理",
|
|
398
|
+
"mcpConnections.noAuthentication": "無需驗證",
|
|
398
399
|
"mcpConnections.settings": "設定",
|
|
399
400
|
"mcpConnections.subtitle": "管理可用於此對話的 MCP 伺服器。",
|
|
400
401
|
"mcpConnections.title": "MCP",
|
|
@@ -504,7 +505,7 @@
|
|
|
504
505
|
"store.actions.changeContentTypeDesc": "變更選中文件的內容類型",
|
|
505
506
|
"store.actions.changeType": "變更類型",
|
|
506
507
|
"store.actions.chooseExistingCollections": "從現有集合中選擇",
|
|
507
|
-
"store.actions.
|
|
508
|
+
"store.actions.chooseWorkflow": "選擇要啟動的工作流程:",
|
|
508
509
|
"store.actions.confirmDeleteAll": "確定要刪除所有選中的物件嗎?此操作無法復原。",
|
|
509
510
|
"store.actions.confirmDeleteSelected": "確定要刪除選中的物件嗎?\n這不是從集合中移除。",
|
|
510
511
|
"store.actions.confirmRemoveFromCollection": "確定要從此集合中移除所選物件嗎?",
|
|
@@ -521,15 +522,18 @@
|
|
|
521
522
|
"store.actions.exportProperties": "匯出屬性",
|
|
522
523
|
"store.actions.noCollectionContext": "沒有集合上下文",
|
|
523
524
|
"store.actions.noObjectsSelected": "未選擇任何物件",
|
|
525
|
+
"store.actions.noWorkflowsAvailable": "沒有可用的工作流程",
|
|
524
526
|
"store.actions.pleaseSelectObjectsToDelete": "請選擇要刪除的物件",
|
|
525
527
|
"store.actions.pleaseSelectObjectsToRemove": "請選擇要從集合中移除的物件",
|
|
526
528
|
"store.actions.removeFromCollection": "從集合中移除",
|
|
527
529
|
"store.actions.removeFromCollectionDesc": "從此集合中移除所選物件",
|
|
528
530
|
"store.actions.selectCollection": "選擇集合",
|
|
531
|
+
"store.actions.start": "啟動",
|
|
529
532
|
"store.actions.startWorkflow": "啟動工作流程",
|
|
530
|
-
"store.actions.startWorkflowByRule": "按規則啟動工作流程",
|
|
531
533
|
"store.actions.startWorkflowDesc": "對選中的物件啟動工作流程",
|
|
532
534
|
"store.actions.workflowStarted": "工作流程已啟動",
|
|
535
|
+
"store.actions.workflowStartedOn_one": "已對 {{count}} 個物件啟動 {{name}}",
|
|
536
|
+
"store.actions.workflowStartedOn_other": "已對 {{count}} 個物件啟動 {{name}}",
|
|
533
537
|
"store.allowedContentTypes": "允許的內容類型",
|
|
534
538
|
"store.allowedContentTypesOptionalDescription": "可選擇限定可新增到集合中的內容類型。如果未設定,則允許所有內容類型。",
|
|
535
539
|
"store.allowedContentTypesSelectDescription": "選擇可新增到集合中的內容類型。如果未設定,則允許所有內容類型。",
|
package/src/i18n/locales/zh.json
CHANGED
|
@@ -395,6 +395,7 @@
|
|
|
395
395
|
"mcpConnections.label": "MCP",
|
|
396
396
|
"mcpConnections.manage": "管理 MCP 连接",
|
|
397
397
|
"mcpConnections.managedByApp": "由应用管理",
|
|
398
|
+
"mcpConnections.noAuthentication": "无需身份验证",
|
|
398
399
|
"mcpConnections.settings": "设置",
|
|
399
400
|
"mcpConnections.subtitle": "管理可用于此对话的 MCP 服务器。",
|
|
400
401
|
"mcpConnections.title": "MCP",
|
|
@@ -504,7 +505,7 @@
|
|
|
504
505
|
"store.actions.changeContentTypeDesc": "更改选中文档的内容类型",
|
|
505
506
|
"store.actions.changeType": "更改类型",
|
|
506
507
|
"store.actions.chooseExistingCollections": "从现有集合中选择",
|
|
507
|
-
"store.actions.
|
|
508
|
+
"store.actions.chooseWorkflow": "选择要启动的工作流:",
|
|
508
509
|
"store.actions.confirmDeleteAll": "确定要删除所有选中的对象吗?此操作无法撤销。",
|
|
509
510
|
"store.actions.confirmDeleteSelected": "确定要删除选中的对象吗?\n这不是从集合中移除。",
|
|
510
511
|
"store.actions.confirmRemoveFromCollection": "确定要从此集合中移除所选对象吗?",
|
|
@@ -521,15 +522,18 @@
|
|
|
521
522
|
"store.actions.exportProperties": "导出属性",
|
|
522
523
|
"store.actions.noCollectionContext": "没有集合上下文",
|
|
523
524
|
"store.actions.noObjectsSelected": "未选择任何对象",
|
|
525
|
+
"store.actions.noWorkflowsAvailable": "没有可用的工作流",
|
|
524
526
|
"store.actions.pleaseSelectObjectsToDelete": "请选择要删除的对象",
|
|
525
527
|
"store.actions.pleaseSelectObjectsToRemove": "请选择要从集合中移除的对象",
|
|
526
528
|
"store.actions.removeFromCollection": "从集合中移除",
|
|
527
529
|
"store.actions.removeFromCollectionDesc": "从此集合中移除所选对象",
|
|
528
530
|
"store.actions.selectCollection": "选择集合",
|
|
531
|
+
"store.actions.start": "启动",
|
|
529
532
|
"store.actions.startWorkflow": "启动工作流",
|
|
530
|
-
"store.actions.startWorkflowByRule": "按规则启动工作流",
|
|
531
533
|
"store.actions.startWorkflowDesc": "对选中的对象启动工作流",
|
|
532
534
|
"store.actions.workflowStarted": "工作流已启动",
|
|
535
|
+
"store.actions.workflowStartedOn_one": "已对 {{count}} 个对象启动 {{name}}",
|
|
536
|
+
"store.actions.workflowStartedOn_other": "已对 {{count}} 个对象启动 {{name}}",
|
|
533
537
|
"store.allowedContentTypes": "允许的内容类型",
|
|
534
538
|
"store.allowedContentTypesOptionalDescription": "可选择限定可添加到集合中的内容类型。如果未设置,则允许所有内容类型。",
|
|
535
539
|
"store.allowedContentTypesSelectDescription": "选择可添加到集合中的内容类型。如果未设置,则允许所有内容类型。",
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { VertesiaClient } from '@vertesia/client';
|
|
2
2
|
import { type AuthTokenPayload, PrincipalType } from '@vertesia/common';
|
|
3
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import * as composable from './auth/composable';
|
|
5
|
+
import * as oauth from './auth/oauth';
|
|
4
6
|
import { UserSession } from './UserSession';
|
|
5
7
|
|
|
8
|
+
afterEach(() => vi.restoreAllMocks());
|
|
9
|
+
|
|
6
10
|
const projectToken: AuthTokenPayload = {
|
|
7
11
|
sub: 'test-user',
|
|
8
12
|
name: 'Test User',
|
|
@@ -33,6 +37,16 @@ function createSession(onboardingProgress: () => Promise<Record<string, boolean>
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
describe('UserSession.fetchOnboardingStatus', () => {
|
|
40
|
+
it.each(['token', 'oauth'] as const)(
|
|
41
|
+
'does not load Studio onboarding for a default %s login',
|
|
42
|
+
async (authMethod) => {
|
|
43
|
+
const onboardingProgress = vi.fn(async () => ({ project_created: true }));
|
|
44
|
+
const { session } = createSession(onboardingProgress);
|
|
45
|
+
await session.login(encodeToken(projectToken), { authMethod });
|
|
46
|
+
expect(onboardingProgress).not.toHaveBeenCalled();
|
|
47
|
+
expect(session.onboardingComplete).toBeUndefined();
|
|
48
|
+
},
|
|
49
|
+
);
|
|
36
50
|
it('skips onboarding before authentication without publishing a status', async () => {
|
|
37
51
|
const onboardingProgress = vi.fn(async () => ({ project_created: true }));
|
|
38
52
|
const { session, setSession } = createSession(onboardingProgress);
|
|
@@ -48,12 +62,12 @@ describe('UserSession.fetchOnboardingStatus', () => {
|
|
|
48
62
|
const onboardingProgress = vi.fn(async () => ({ project_created: true }));
|
|
49
63
|
const { session, setSession } = createSession(onboardingProgress);
|
|
50
64
|
|
|
51
|
-
await session.login(encodeToken({ ...projectToken, project: undefined }));
|
|
65
|
+
await session.login(encodeToken({ ...projectToken, project: undefined }), { loadOnboardingStatus: true });
|
|
52
66
|
expect(onboardingProgress).not.toHaveBeenCalled();
|
|
53
67
|
expect(session.onboardingComplete).toBeUndefined();
|
|
54
68
|
expect(setSession).not.toHaveBeenCalled();
|
|
55
69
|
|
|
56
|
-
await session.login(encodeToken(projectToken));
|
|
70
|
+
await session.login(encodeToken(projectToken), { loadOnboardingStatus: true });
|
|
57
71
|
expect(onboardingProgress).toHaveBeenCalledOnce();
|
|
58
72
|
expect(session.onboardingComplete).toBe(true);
|
|
59
73
|
expect(setSession).toHaveBeenCalledOnce();
|
|
@@ -102,3 +116,34 @@ describe('UserSession.signOut', () => {
|
|
|
102
116
|
expect(logout).toHaveBeenCalledOnce();
|
|
103
117
|
});
|
|
104
118
|
});
|
|
119
|
+
|
|
120
|
+
describe('UserSession credential provider', () => {
|
|
121
|
+
it('keeps the accepted token session after the fragment state is consumed', async () => {
|
|
122
|
+
const rawToken = encodeToken(projectToken);
|
|
123
|
+
vi.spyOn(composable, 'getComposableToken').mockResolvedValue({ rawToken, token: projectToken, error: false });
|
|
124
|
+
const acquireOAuth = vi.spyOn(oauth, 'getAppOAuthToken').mockResolvedValue('oauth-token');
|
|
125
|
+
// OAuth is configured again after the one-time fragment nonce is cleared.
|
|
126
|
+
vi.spyOn(oauth, 'usesAppOAuth').mockReturnValue(true);
|
|
127
|
+
const { session } = createSession(async () => ({}));
|
|
128
|
+
await session.login(rawToken, { loadOnboardingStatus: false });
|
|
129
|
+
|
|
130
|
+
await expect(session.authCallback).resolves.toBe(`Bearer ${rawToken}`);
|
|
131
|
+
await expect(session.clone().authCallback).resolves.toBe(`Bearer ${rawToken}`);
|
|
132
|
+
await session.refreshAuthToken();
|
|
133
|
+
expect(acquireOAuth).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('retains OAuth acquisition and refresh for OAuth logins and cloned sessions', async () => {
|
|
137
|
+
const rawToken = encodeToken({ ...projectToken, type: PrincipalType.OAuthAccess });
|
|
138
|
+
const acquireOAuth = vi.spyOn(oauth, 'getAppOAuthToken').mockResolvedValue(rawToken);
|
|
139
|
+
const acquireLegacy = vi.spyOn(composable, 'getComposableToken');
|
|
140
|
+
const { session } = createSession(async () => ({}));
|
|
141
|
+
await session.login(rawToken, { loadOnboardingStatus: false, authMethod: 'oauth' });
|
|
142
|
+
|
|
143
|
+
await expect(session.authCallback).resolves.toBe(`Bearer ${rawToken}`);
|
|
144
|
+
await expect(session.clone().authCallback).resolves.toBe(`Bearer ${rawToken}`);
|
|
145
|
+
await session.refreshAuthToken();
|
|
146
|
+
expect(acquireOAuth).toHaveBeenCalledWith(true);
|
|
147
|
+
expect(acquireLegacy).not.toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
@@ -8,17 +8,20 @@ import { getComposableToken } from './auth/composable';
|
|
|
8
8
|
import { authReturnUrl, centralAuthUrl, mountRootUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
|
|
9
9
|
import { getFirebaseAuth } from './auth/firebase';
|
|
10
10
|
import { gatewayFetch, loadGatewaySession, logoutGatewaySession, usesGatewaySession } from './auth/gateway';
|
|
11
|
-
import {
|
|
11
|
+
import { getAppOAuthToken, revokeAppOAuthSession } from './auth/oauth';
|
|
12
12
|
|
|
13
13
|
import { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from './constants';
|
|
14
14
|
|
|
15
15
|
export { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY };
|
|
16
16
|
|
|
17
17
|
export interface UserSessionLoginOptions {
|
|
18
|
+
/** Studio-only onboarding; custom apps leave this disabled. */
|
|
18
19
|
loadOnboardingStatus?: boolean;
|
|
20
|
+
authMethod?: 'token' | 'oauth';
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
class UserSession {
|
|
24
|
+
private authMethod: 'token' | 'oauth' = 'token';
|
|
22
25
|
isLoading = true;
|
|
23
26
|
client: VertesiaClient;
|
|
24
27
|
authError?: Error;
|
|
@@ -80,7 +83,7 @@ class UserSession {
|
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
get rawAuthToken() {
|
|
83
|
-
if (
|
|
86
|
+
if (this.authMethod === 'oauth') return getAppOAuthToken();
|
|
84
87
|
if (usesGatewaySession())
|
|
85
88
|
return Promise.reject(new Error('Gateway session credentials are not available to application JavaScript'));
|
|
86
89
|
return getComposableToken().then((res) => {
|
|
@@ -104,9 +107,8 @@ class UserSession {
|
|
|
104
107
|
this.setSession?.(this.clone());
|
|
105
108
|
return payload;
|
|
106
109
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
this.authToken = jwtDecode<AuthTokenPayload>(await getAppOAuthToken());
|
|
110
|
+
if (this.authMethod === 'oauth') {
|
|
111
|
+
this.authToken = jwtDecode<AuthTokenPayload>(await getAppOAuthToken(true));
|
|
110
112
|
this.setSession?.(this.clone());
|
|
111
113
|
return this.authToken;
|
|
112
114
|
}
|
|
@@ -130,6 +132,8 @@ class UserSession {
|
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
async login(token: string, options: UserSessionLoginOptions = {}) {
|
|
135
|
+
// Bind credential lookup to the completed login, not the transient URL hash/state.
|
|
136
|
+
this.authMethod = options.authMethod ?? 'token';
|
|
133
137
|
this.authError = undefined;
|
|
134
138
|
this.isLoading = false;
|
|
135
139
|
this.client.withAuthCallback(() => this.authCallback);
|
|
@@ -147,7 +151,7 @@ class UserSession {
|
|
|
147
151
|
// notify the host app of the login
|
|
148
152
|
Env.onLogin?.(this.authToken);
|
|
149
153
|
|
|
150
|
-
if (options.loadOnboardingStatus
|
|
154
|
+
if (options.loadOnboardingStatus) {
|
|
151
155
|
await this.fetchOnboardingStatus();
|
|
152
156
|
}
|
|
153
157
|
|
|
@@ -185,8 +189,15 @@ class UserSession {
|
|
|
185
189
|
return;
|
|
186
190
|
}
|
|
187
191
|
|
|
188
|
-
if (
|
|
189
|
-
|
|
192
|
+
if (this.authMethod === 'oauth') {
|
|
193
|
+
void revokeAppOAuthSession()
|
|
194
|
+
.catch(() => undefined)
|
|
195
|
+
.finally(() => {
|
|
196
|
+
const logoutUrl = new URL(centralAuthUrl());
|
|
197
|
+
logoutUrl.pathname = '/logout';
|
|
198
|
+
logoutUrl.searchParams.set('redirect_uri', authReturnUrl().toString());
|
|
199
|
+
location.replace(logoutUrl.toString());
|
|
200
|
+
});
|
|
190
201
|
this.client.withAuthCallback(undefined);
|
|
191
202
|
this.authToken = undefined;
|
|
192
203
|
this.authError = undefined;
|
|
@@ -336,6 +347,7 @@ class UserSession {
|
|
|
336
347
|
session.isLoading = this.isLoading;
|
|
337
348
|
session.authError = this.authError;
|
|
338
349
|
session.authToken = this.authToken;
|
|
350
|
+
session.authMethod = this.authMethod;
|
|
339
351
|
session.setSession = this.setSession;
|
|
340
352
|
session.lastSelectedAccount = this.lastSelectedAccount;
|
|
341
353
|
session.switchAccount = this.switchAccount;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { cleanup, render, waitFor } from '@testing-library/react';
|
|
2
|
+
import { type AuthTokenPayload, PrincipalType } from '@vertesia/common';
|
|
3
|
+
import { Env } from '@vertesia/ui/env';
|
|
4
|
+
import { useEffect } from 'react';
|
|
5
|
+
import { afterEach, expect, it, vi } from 'vitest';
|
|
6
|
+
import { generateAuthState } from './auth/authState';
|
|
7
|
+
import { getComposableToken } from './auth/composable';
|
|
8
|
+
import { usesAppOAuth } from './auth/oauth';
|
|
9
|
+
import { useUserSession } from './UserSession';
|
|
10
|
+
import { UserSessionProvider } from './UserSessionProvider';
|
|
11
|
+
|
|
12
|
+
// Only the credential exchange boundary is stubbed. Provider selection, nonce consumption,
|
|
13
|
+
// session cloning, and the SDK authorization callback run together.
|
|
14
|
+
vi.mock('./auth/composable', async (original) => ({
|
|
15
|
+
...(await original<typeof import('./auth/composable')>()),
|
|
16
|
+
getComposableToken: vi.fn(),
|
|
17
|
+
}));
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
cleanup();
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
vi.unstubAllGlobals();
|
|
22
|
+
window.history.replaceState(null, '', '/');
|
|
23
|
+
sessionStorage.clear();
|
|
24
|
+
localStorage.clear();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it.each(
|
|
28
|
+
['/oauth/device?user_code=ABCD-EFGH', '/oauth/authorize/request-id', '/cli'].flatMap((path) =>
|
|
29
|
+
['token', 'oauth'].map((method) => ({ path, method })),
|
|
30
|
+
),
|
|
31
|
+
)('keeps the $method session API callback on $path', async ({ path, method }) => {
|
|
32
|
+
const issuer = 'https://sts.dev1.vertesia.io';
|
|
33
|
+
const clientId = 'https://api.dev1.vertesia.io/.well-known/oauth-client/vertesia-studio';
|
|
34
|
+
const claims: AuthTokenPayload = {
|
|
35
|
+
sub: 'user',
|
|
36
|
+
user_id: 'user',
|
|
37
|
+
name: 'Test User',
|
|
38
|
+
type: method === 'oauth' ? PrincipalType.OAuthAccess : PrincipalType.User,
|
|
39
|
+
iss: issuer,
|
|
40
|
+
apps: [],
|
|
41
|
+
accounts: [],
|
|
42
|
+
account_roles: [],
|
|
43
|
+
aud: issuer,
|
|
44
|
+
account: { id: 'a', name: 'Account' },
|
|
45
|
+
project: { id: 'p', name: 'Project', account: 'a' },
|
|
46
|
+
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
47
|
+
};
|
|
48
|
+
const token = `e30.${btoa(JSON.stringify(claims))}.signature`;
|
|
49
|
+
Env.init({
|
|
50
|
+
name: 'test',
|
|
51
|
+
version: '1',
|
|
52
|
+
type: 'production',
|
|
53
|
+
isLocalDev: false,
|
|
54
|
+
isDocker: false,
|
|
55
|
+
endpoints: { studio: 'https://api.dev1.vertesia.io', zeno: 'https://api.dev1.vertesia.io', sts: issuer },
|
|
56
|
+
oauth: {
|
|
57
|
+
clientId,
|
|
58
|
+
redirectUri: `${window.location.origin}/oauth/callback`,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
const url = new URL(path, window.location.origin);
|
|
62
|
+
url.searchParams.set('a', 'a');
|
|
63
|
+
url.searchParams.set('p', 'p');
|
|
64
|
+
if (method === 'token') {
|
|
65
|
+
const state = generateAuthState();
|
|
66
|
+
url.hash = `token=${token}&state=${state}`;
|
|
67
|
+
vi.mocked(getComposableToken).mockResolvedValue({ rawToken: token, token: claims, error: false });
|
|
68
|
+
} else {
|
|
69
|
+
// Seed only synthetic credentials and public fixture metadata, never runtime auth configuration.
|
|
70
|
+
sessionStorage.setItem(
|
|
71
|
+
'vertesia.oauth.access',
|
|
72
|
+
JSON.stringify({
|
|
73
|
+
token,
|
|
74
|
+
issuer,
|
|
75
|
+
clientId,
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
vi.mocked(getComposableToken).mockRejectedValue(new Error('OAuth must not use the legacy exchange'));
|
|
79
|
+
}
|
|
80
|
+
window.history.replaceState(null, '', url.toString());
|
|
81
|
+
const received = vi.fn();
|
|
82
|
+
const failed = vi.fn();
|
|
83
|
+
function Probe() {
|
|
84
|
+
const session = useUserSession();
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (session.user) void session.clone().authCallback.then(received).catch(failed);
|
|
87
|
+
}, [session]);
|
|
88
|
+
return <span>{session.user?.name}</span>;
|
|
89
|
+
}
|
|
90
|
+
const view = render(
|
|
91
|
+
<UserSessionProvider>
|
|
92
|
+
<Probe />
|
|
93
|
+
</UserSessionProvider>,
|
|
94
|
+
);
|
|
95
|
+
await view.findByText('Test User');
|
|
96
|
+
await waitFor(() => expect(window.location.hash).toBe(''));
|
|
97
|
+
expect(sessionStorage.getItem('auth_state')).toBeNull();
|
|
98
|
+
expect(usesAppOAuth()).toBe(true);
|
|
99
|
+
await waitFor(() => expect(received).toHaveBeenCalledWith(`Bearer ${token}`));
|
|
100
|
+
expect(failed).not.toHaveBeenCalled();
|
|
101
|
+
if (method === 'oauth') expect(getComposableToken).not.toHaveBeenCalled();
|
|
102
|
+
expect(sessionStorage.getItem('vertesia.oauth.transaction')).toBeNull();
|
|
103
|
+
});
|