@vertesia/ui 1.4.0-dev.20260615.051508Z → 1.4.0-dev.20260629.130134Z
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/core/components/shadcn/dropdown.d.ts.map +1 -1
- package/lib/core/components/shadcn/dropdown.js +6 -2
- package/lib/core/components/shadcn/dropdown.js.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.js +9 -2
- package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.d.ts +16 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.d.ts.map +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.js +25 -3
- package/lib/core/components/shadcn/modal/ConfirmModal.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +1 -1
- package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
- package/lib/core/components/shadcn/popover.d.ts.map +1 -1
- package/lib/core/components/shadcn/popover.js +3 -1
- package/lib/core/components/shadcn/popover.js.map +1 -1
- package/lib/core/components/shadcn/switch.js +3 -3
- package/lib/core/components/shadcn/switch.js.map +1 -1
- package/lib/core/components/shadcn/tabs.js +1 -1
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/core/components/shadcn/tooltip.d.ts.map +1 -1
- package/lib/core/components/shadcn/tooltip.js +3 -1
- package/lib/core/components/shadcn/tooltip.js.map +1 -1
- package/lib/env/index.d.ts +0 -19
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +0 -6
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/PayloadBuilder.d.ts +4 -0
- package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
- package/lib/features/agent/PayloadBuilder.js +16 -0
- package/lib/features/agent/PayloadBuilder.js.map +1 -1
- package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts +10 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts.map +1 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.js +50 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.js.map +1 -0
- package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts +2 -1
- package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentChatFixtureReplay.js +3 -3
- package/lib/features/agent/chat/AgentChatFixtureReplay.js.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +5 -2
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.js +41 -7
- package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +133 -12
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/AnimatedThinkingDots.js +1 -1
- package/lib/features/agent/chat/AnimatedThinkingDots.js.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js +11 -65
- package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts +3 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.js +4 -3
- package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts +10 -2
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +526 -117
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts +8 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +19 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +8 -2
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +551 -92
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +7 -6
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts +8 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js +61 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +15 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +28 -38
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +3 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts +5 -0
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +59 -4
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +9 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +180 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.js +92 -2
- package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
- package/lib/features/agent/chat/clipboardFiles.d.ts +15 -0
- package/lib/features/agent/chat/clipboardFiles.d.ts.map +1 -0
- package/lib/features/agent/chat/clipboardFiles.js +35 -0
- package/lib/features/agent/chat/clipboardFiles.js.map +1 -0
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts +6 -0
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.js +218 -37
- package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts +1 -8
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.js +10 -28
- package/lib/features/agent/chat/hooks/useArtifacts.js.map +1 -1
- package/lib/features/agent/chat/index.d.ts +2 -1
- package/lib/features/agent/chat/index.d.ts.map +1 -1
- package/lib/features/agent/chat/index.js +2 -1
- package/lib/features/agent/chat/index.js.map +1 -1
- package/lib/features/agent/chat/workstreams.d.ts +1 -0
- package/lib/features/agent/chat/workstreams.d.ts.map +1 -1
- package/lib/features/agent/chat/workstreams.js +28 -0
- package/lib/features/agent/chat/workstreams.js.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts +10 -1
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.js +6 -3
- package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.d.ts +10 -1
- package/lib/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.js +14 -5
- package/lib/features/facets/CollectionsFacetsNav.js.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts +10 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.js +14 -5
- package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
- package/lib/features/facets/RunsFacetsNav.d.ts +10 -1
- package/lib/features/facets/RunsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/RunsFacetsNav.js +14 -5
- package/lib/features/facets/RunsFacetsNav.js.map +1 -1
- package/lib/features/index.d.ts +0 -1
- package/lib/features/index.d.ts.map +1 -1
- package/lib/features/index.js +0 -1
- package/lib/features/index.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts +30 -0
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -0
- package/lib/features/oauth/McpConnectionsButton.js +70 -0
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -0
- package/lib/features/oauth/McpConnectionsDialog.d.ts +25 -0
- package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -0
- package/lib/features/oauth/McpConnectionsDialog.js +26 -0
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -0
- package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.js +14 -6
- package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
- package/lib/features/oauth/index.d.ts +3 -0
- package/lib/features/oauth/index.d.ts.map +1 -1
- package/lib/features/oauth/index.js +3 -0
- package/lib/features/oauth/index.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +44 -0
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -0
- package/lib/features/oauth/useMcpConnections.js +168 -0
- package/lib/features/oauth/useMcpConnections.js.map +1 -0
- package/lib/features/permissions/UserPermissionsProvider.d.ts +4 -6
- package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.js +40 -42
- package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js +2 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
- package/lib/features/store/objects/DocumentQuickFilter.d.ts +23 -0
- package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -0
- package/lib/features/store/objects/DocumentQuickFilter.js +30 -0
- package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -0
- package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.js +17 -1
- package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +17 -74
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.d.ts +7 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.d.ts.map +1 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.js +27 -3
- package/lib/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
- package/lib/features/store/objects/layout/documentLayout.js +1 -1
- package/lib/features/store/objects/layout/renderers.d.ts +2 -1
- package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
- package/lib/features/store/objects/layout/renderers.js +27 -20
- package/lib/features/store/objects/layout/renderers.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesSearch.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesSearch.js +4 -1
- package/lib/features/store/types/ContentObjectTypesSearch.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts +2 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.js +8 -3
- package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
- package/lib/i18n/instance.d.ts.map +1 -1
- package/lib/i18n/instance.js +1 -0
- package/lib/i18n/instance.js.map +1 -1
- package/lib/i18n/locales/ar.json +72 -45
- package/lib/i18n/locales/de.json +65 -34
- package/lib/i18n/locales/en.json +63 -47
- package/lib/i18n/locales/es.json +65 -35
- package/lib/i18n/locales/fr.json +65 -35
- package/lib/i18n/locales/it.json +72 -42
- package/lib/i18n/locales/ja.json +72 -41
- package/lib/i18n/locales/ko.json +72 -41
- package/lib/i18n/locales/pt.json +72 -42
- package/lib/i18n/locales/ru.json +72 -43
- package/lib/i18n/locales/tr.json +72 -41
- package/lib/i18n/locales/zh-TW.json +72 -41
- package/lib/i18n/locales/zh.json +72 -41
- package/lib/session/UserSession.d.ts +0 -6
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +0 -15
- package/lib/session/UserSession.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +39 -98
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/composable.d.ts.map +1 -1
- package/lib/session/auth/composable.js +3 -33
- package/lib/session/auth/composable.js.map +1 -1
- package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
- package/lib/shell/login/SignInPrimitives.js +3 -2
- package/lib/shell/login/SignInPrimitives.js.map +1 -1
- package/lib/vertesia-ui-core.js +1 -1
- 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 +1 -1
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.js +1 -1
- package/lib/vertesia-ui-i18n.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 +1 -1
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +1 -1
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/schema-editor/editor/Editable.js +1 -1
- package/lib/widgets/schema-editor/editor/Editable.js.map +1 -1
- package/llms.txt +70 -70
- package/package.json +35 -32
- package/src/core/components/shadcn/dropdown.tsx +2 -0
- package/src/core/components/shadcn/filters/filterBar.tsx +9 -2
- package/src/core/components/shadcn/modal/ConfirmModal.tsx +65 -3
- package/src/core/components/shadcn/modal/dialog.tsx +1 -1
- package/src/core/components/shadcn/popover.tsx +1 -0
- package/src/core/components/shadcn/switch.tsx +4 -4
- package/src/core/components/shadcn/tabs.tsx +1 -1
- package/src/core/components/shadcn/tooltip.tsx +1 -0
- package/src/env/index.ts +0 -24
- package/src/features/agent/PayloadBuilder.tsx +18 -0
- package/src/features/agent/chat/AgentApprovalModeSelector.tsx +130 -0
- package/src/features/agent/chat/AgentChatFixtureReplay.test.tsx +22 -2
- package/src/features/agent/chat/AgentChatFixtureReplay.tsx +33 -27
- package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +122 -0
- package/src/features/agent/chat/AgentRequestInputOverlay.tsx +91 -17
- package/src/features/agent/chat/AgentRightPanel.tsx +238 -50
- package/src/features/agent/chat/AnimatedThinkingDots.tsx +1 -1
- package/src/features/agent/chat/ArtifactsTab.tsx +21 -155
- package/src/features/agent/chat/AskUserWidget.tsx +6 -2
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +1157 -47
- package/src/features/agent/chat/ModernAgentConversation.tsx +703 -136
- package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +74 -0
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +1420 -126
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +934 -111
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +31 -40
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +28 -28
- package/src/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.tsx +83 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +38 -2
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +121 -98
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +7 -1
- package/src/features/agent/chat/ModernAgentOutput/SlideInPanel.tsx +3 -3
- package/src/features/agent/chat/ModernAgentOutput/SlidingMessages.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +82 -2
- package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +2 -2
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +216 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +149 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.ts +103 -2
- package/src/features/agent/chat/clipboardFiles.ts +33 -0
- package/src/features/agent/chat/hooks/useAgentStream.test.tsx +355 -4
- package/src/features/agent/chat/hooks/useAgentStream.ts +270 -43
- package/src/features/agent/chat/hooks/useArtifacts.ts +11 -44
- package/src/features/agent/chat/index.ts +10 -1
- package/src/features/agent/chat/workstreams.ts +42 -0
- package/src/features/facets/AgentRunnerFacetsNav.tsx +23 -3
- package/src/features/facets/CollectionsFacetsNav.tsx +30 -5
- package/src/features/facets/PromptsFacetsNav.tsx +30 -5
- package/src/features/facets/RunsFacetsNav.tsx +32 -5
- package/src/features/index.ts +0 -1
- package/src/features/oauth/McpConnectionsButton.test.tsx +248 -0
- package/src/features/oauth/McpConnectionsButton.tsx +269 -0
- package/src/features/oauth/McpConnectionsDialog.tsx +142 -0
- package/src/features/oauth/RemoteMcpConnectionButton.tsx +37 -14
- package/src/features/oauth/index.ts +3 -0
- package/src/features/oauth/useMcpConnections.test.ts +94 -0
- package/src/features/oauth/useMcpConnections.ts +210 -0
- package/src/features/permissions/UserPermissionsProvider.tsx +41 -59
- package/src/features/store/objects/DocumentPreviewPanel.tsx +4 -2
- package/src/features/store/objects/DocumentQuickFilter.tsx +72 -0
- package/src/features/store/objects/DocumentSearchResults.tsx +30 -11
- package/src/features/store/objects/components/ContentOverview.tsx +30 -99
- package/src/features/store/objects/layout/DocumentTableColumn.tsx +29 -4
- package/src/features/store/objects/layout/documentLayout.tsx +1 -1
- package/src/features/store/objects/layout/renderers.tsx +80 -20
- package/src/features/store/types/ContentObjectTypesSearch.tsx +7 -1
- package/src/features/store/types/ContentObjectTypesTable.tsx +34 -4
- package/src/i18n/instance.ts +1 -0
- package/src/i18n/locales/ar.json +72 -45
- package/src/i18n/locales/de.json +65 -34
- package/src/i18n/locales/en.json +63 -47
- package/src/i18n/locales/es.json +65 -35
- package/src/i18n/locales/fr.json +65 -35
- package/src/i18n/locales/it.json +72 -42
- package/src/i18n/locales/ja.json +72 -41
- package/src/i18n/locales/ko.json +72 -41
- package/src/i18n/locales/pt.json +72 -42
- package/src/i18n/locales/ru.json +72 -43
- package/src/i18n/locales/tr.json +72 -41
- package/src/i18n/locales/zh-TW.json +72 -41
- package/src/i18n/locales/zh.json +72 -41
- package/src/i18n/rtl.test.ts +57 -1
- package/src/session/UserSession.ts +0 -16
- package/src/session/UserSessionProvider.tsx +51 -123
- package/src/session/auth/composable.ts +3 -34
- package/src/shell/login/SignInPrimitives.tsx +3 -2
- package/src/widgets/schema-editor/editor/Editable.tsx +1 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts +0 -73
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +0 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.js +0 -415
- package/lib/features/document-viewer/UniversalDocumentViewer.js.map +0 -1
- package/lib/features/document-viewer/index.d.ts +0 -2
- package/lib/features/document-viewer/index.d.ts.map +0 -1
- package/lib/features/document-viewer/index.js +0 -2
- package/lib/features/document-viewer/index.js.map +0 -1
- package/src/features/document-viewer/UniversalDocumentViewer.test.tsx +0 -123
- package/src/features/document-viewer/UniversalDocumentViewer.tsx +0 -746
- package/src/features/document-viewer/index.ts +0 -1
- package/src/session/auth/composable.test.ts +0 -79
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertesia-ui-i18n.js","sources":["i18n/instance.js","i18n/rtl.js","i18n/LanguageProvider.js","i18n/useLocaleFormat.js","i18n/index.js"],"sourcesContent":["import i18next from 'i18next';\nimport { initReactI18next } from 'react-i18next';\nimport ar from './locales/ar.json';\nimport de from './locales/de.json';\nimport en from './locales/en.json';\nimport es from './locales/es.json';\nimport fr from './locales/fr.json';\nimport it from './locales/it.json';\nimport ja from './locales/ja.json';\nimport ko from './locales/ko.json';\nimport pt from './locales/pt.json';\nimport ru from './locales/ru.json';\nimport tr from './locales/tr.json';\nimport zh from './locales/zh.json';\nimport zhTW from './locales/zh-TW.json';\nexport const NAMESPACE = 'vertesia.ui';\n// Scoped instance — does NOT touch the global i18next singleton\nconst i18nInstance = i18next.createInstance();\nvoid i18nInstance.use(initReactI18next).init({\n resources: {\n ar: { [NAMESPACE]: ar },\n de: { [NAMESPACE]: de },\n en: { [NAMESPACE]: en },\n es: { [NAMESPACE]: es },\n fr: { [NAMESPACE]: fr },\n it: { [NAMESPACE]: it },\n ja: { [NAMESPACE]: ja },\n ko: { [NAMESPACE]: ko },\n pt: { [NAMESPACE]: pt },\n ru: { [NAMESPACE]: ru },\n tr: { [NAMESPACE]: tr },\n zh: { [NAMESPACE]: zh },\n 'zh-TW': { [NAMESPACE]: zhTW },\n },\n fallbackLng: 'en',\n ns: [NAMESPACE],\n defaultNS: NAMESPACE,\n interpolation: {\n escapeValue: false, // React already escapes\n },\n react: {\n useSuspense: false, // Translations are bundled, no async loading\n },\n});\nexport { i18nInstance };\n//# sourceMappingURL=instance.js.map","/**\n * RTL detection and language resolution for the @vertesia/ui locale set.\n *\n * SUPPORTED_LANGUAGES is the single source of truth for what locales the\n * switcher offers, and must stay in sync with the resources registered in\n * `./instance.ts`. A divergence-guard test (`./rtl.test.ts`) fails the build\n * if the two diverge.\n *\n * RTL_LANGUAGES is deliberately broader than SUPPORTED_LANGUAGES so that\n * dir=\"rtl\" handling is forward-compatible when new RTL locales (he, fa, ur,\n * ...) are added to instance.ts later.\n */\nexport const SUPPORTED_LANGUAGES = [\n 'ar',\n 'de',\n 'en',\n 'es',\n 'fr',\n 'it',\n 'ja',\n 'ko',\n 'pt',\n 'ru',\n 'tr',\n 'zh',\n 'zh-TW',\n];\nexport const RTL_LANGUAGES = new Set(['ar', 'he', 'fa', 'ur']);\nexport function isRTL(lng) {\n if (!lng)\n return false;\n return RTL_LANGUAGES.has(lng.split('-')[0].toLowerCase());\n}\n/**\n * Resolve any raw language code (BCP-47 or bare) to a SupportedLanguage:\n * 1. exact match against SUPPORTED_LANGUAGES (preserves `zh-TW` vs `zh`)\n * 2. base-language fallback (`pt-BR` -> `pt`)\n * 3. `'en'` fallback\n *\n * The inline FOUC script in `index.html` must reimplement this same logic\n * verbatim (it cannot import ESM before bundle load).\n */\nexport function resolveLanguage(raw) {\n if (!raw)\n return 'en';\n const list = SUPPORTED_LANGUAGES;\n if (list.includes(raw))\n return raw;\n const base = raw.split('-')[0];\n if (list.includes(base))\n return base;\n return 'en';\n}\n//# sourceMappingURL=rtl.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { DirectionProvider } from '@radix-ui/react-direction';\nimport { createContext, useContext, useEffect, useMemo, useState } from 'react';\nimport { isRTL, resolveLanguage } from './rtl.js';\nconst initialState = {\n language: 'en',\n setLanguage: () => null,\n isRTL: false,\n};\nconst LanguageProviderContext = createContext(initialState);\nexport { LanguageProviderContext };\nfunction readInitialLanguage(storageKey, defaultLanguage) {\n if (typeof window === 'undefined')\n return defaultLanguage;\n const stored = window.localStorage?.getItem(storageKey);\n if (stored)\n return resolveLanguage(stored);\n const nav = window.navigator?.language;\n if (nav)\n return resolveLanguage(nav);\n return defaultLanguage;\n}\nexport function LanguageProvider({ children, defaultLanguage = 'en', storageKey = 'vertesia-ui-language', ...props }) {\n const [language, setLanguage] = useState(() => readInitialLanguage(storageKey, defaultLanguage));\n const rtl = isRTL(language);\n useEffect(() => {\n const root = window.document.documentElement;\n root.lang = language;\n root.dir = rtl ? 'rtl' : 'ltr';\n }, [language, rtl]);\n const value = useMemo(() => ({\n language,\n isRTL: rtl,\n setLanguage: (next) => {\n window.localStorage?.setItem(storageKey, next);\n setLanguage(next);\n },\n }), [language, rtl, storageKey]);\n return (_jsx(LanguageProviderContext.Provider, { ...props, value: value, children: _jsx(DirectionProvider, { dir: rtl ? 'rtl' : 'ltr', children: children }) }));\n}\nexport function useLanguage() {\n const context = useContext(LanguageProviderContext);\n if (context === undefined) {\n throw new Error('useLanguage must be used within a LanguageProvider');\n }\n return context;\n}\n//# sourceMappingURL=LanguageProvider.js.map","import { useMemo } from 'react';\nimport { useLanguage } from './LanguageProvider.js';\nfunction toDate(input) {\n if (input == null)\n return null;\n const d = input instanceof Date ? input : new Date(input);\n return Number.isNaN(d.getTime()) ? null : d;\n}\nconst PLACEHOLDER = '—';\nconst RELATIVE_UNITS = [\n { unit: 'year', seconds: 31536000 },\n { unit: 'month', seconds: 2628000 },\n { unit: 'week', seconds: 604800 },\n { unit: 'day', seconds: 86400 },\n { unit: 'hour', seconds: 3600 },\n { unit: 'minute', seconds: 60 },\n { unit: 'second', seconds: 1 },\n];\nexport function useLocaleFormat() {\n const { language } = useLanguage();\n return useMemo(() => {\n // dateStyle: 'long' so each locale shows its native flavor — Japanese\n // gets 年月日 markers, English gets \"May 11, 2026\", Arabic gets month\n // names, etc. The 'short' style is too aggressively numeric (it\n // renders Japanese as \"2026/05/11\", which is correct per CLDR but\n // doesn't feel localized to users). Call sites that want compact\n // numeric output can pass `{ dateStyle: 'short' }` explicitly.\n const dateLong = new Intl.DateTimeFormat(language, { dateStyle: 'long' });\n const dateTimeLong = new Intl.DateTimeFormat(language, { dateStyle: 'long', timeStyle: 'short' });\n const timeShort = new Intl.DateTimeFormat(language, { timeStyle: 'short' });\n const numberDefault = new Intl.NumberFormat(language);\n const relativeDefault = new Intl.RelativeTimeFormat(language, { numeric: 'auto' });\n const listDefault = new Intl.ListFormat(language);\n return {\n language,\n formatDate: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n return options ? new Intl.DateTimeFormat(language, options).format(d) : dateLong.format(d);\n },\n formatDateTime: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n return options ? new Intl.DateTimeFormat(language, options).format(d) : dateTimeLong.format(d);\n },\n formatTime: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n return options ? new Intl.DateTimeFormat(language, options).format(d) : timeShort.format(d);\n },\n formatNumber: (value, options) => {\n if (value == null || Number.isNaN(value))\n return PLACEHOLDER;\n return options ? new Intl.NumberFormat(language, options).format(value) : numberDefault.format(value);\n },\n formatRelativeTime: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n const diffSeconds = (d.getTime() - Date.now()) / 1000;\n const abs = Math.abs(diffSeconds);\n const { unit, seconds } = RELATIVE_UNITS.find((u) => abs >= u.seconds) ?? RELATIVE_UNITS[RELATIVE_UNITS.length - 1];\n const value = Math.round(diffSeconds / seconds);\n const formatter = options ? new Intl.RelativeTimeFormat(language, options) : relativeDefault;\n return formatter.format(value, unit);\n },\n formatList: (items, options) => {\n const filtered = items.filter((v) => v != null && v !== '');\n if (filtered.length === 0)\n return '';\n return options ? new Intl.ListFormat(language, options).format(filtered) : listDefault.format(filtered);\n },\n };\n }, [language]);\n}\n//# sourceMappingURL=useLocaleFormat.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect } from 'react';\nimport { I18nextProvider, Trans, useTranslation } from 'react-i18next';\nimport { i18nInstance, NAMESPACE } from './instance.js';\nimport { useLanguage } from './LanguageProvider.js';\nexport { Trans };\nfunction detectLanguage(lng) {\n return lng ?? navigator.language?.split('-')[0] ?? 'en';\n}\nexport function I18nProvider({ lng, children }) {\n // Set language synchronously on first render to avoid flash of wrong language\n const language = detectLanguage(lng);\n if (i18nInstance.language !== language) {\n void i18nInstance.changeLanguage(language);\n }\n // Also react to prop changes\n useEffect(() => {\n const lang = detectLanguage(lng);\n if (i18nInstance.language !== lang) {\n void i18nInstance.changeLanguage(lang);\n }\n }, [lng]);\n return _jsx(I18nextProvider, { i18n: i18nInstance, children: children });\n}\n/**\n * Binds i18next to the language reported by the surrounding `LanguageProvider`.\n * Use this inside `VertesiaShell` (or wherever a `LanguageProvider` ancestor is\n * available) so language changes propagate to all `useUITranslation()` callers\n * without a static `lng` prop.\n */\nexport function LanguageBoundI18nProvider({ children }) {\n const { language } = useLanguage();\n return _jsx(I18nProvider, { lng: language, children: children });\n}\n/**\n * Hook for components inside @vertesia/ui to get translation functions.\n * Always binds to the 'vertesia.ui' namespace on the scoped instance.\n */\nexport function useUITranslation() {\n return useTranslation(NAMESPACE, { i18n: i18nInstance });\n}\nexport { i18nInstance, NAMESPACE } from './instance.js';\nexport { LanguageProvider, LanguageProviderContext, useLanguage, } from './LanguageProvider.js';\nexport { isRTL, RTL_LANGUAGES, resolveLanguage, SUPPORTED_LANGUAGES, } from './rtl.js';\nexport { useLocaleFormat } from './useLocaleFormat.js';\n//# sourceMappingURL=index.js.map"],"names":["NAMESPACE","i18nInstance","i18next","createInstance","use","initReactI18next","init","resources","ar","de","en","es","fr","it","ja","ko","pt","ru","tr","zh","fallbackLng","ns","defaultNS","interpolation","escapeValue","react","useSuspense","SUPPORTED_LANGUAGES","RTL_LANGUAGES","Set","isRTL","lng","has","split","toLowerCase","resolveLanguage","raw","list","includes","base","LanguageProviderContext","createContext","language","setLanguage","LanguageProvider","children","defaultLanguage","storageKey","props","useState","window","stored","localStorage","getItem","nav","navigator","readInitialLanguage","rtl","useEffect","root","document","documentElement","lang","dir","value","useMemo","next","setItem","_jsx","Provider","DirectionProvider","useLanguage","context","useContext","undefined","Error","toDate","input","d","Date","Number","isNaN","getTime","PLACEHOLDER","RELATIVE_UNITS","unit","seconds","useLocaleFormat","dateLong","Intl","DateTimeFormat","dateStyle","dateTimeLong","timeStyle","timeShort","numberDefault","NumberFormat","relativeDefault","RelativeTimeFormat","numeric","listDefault","ListFormat","formatDate","date","options","format","formatDateTime","formatTime","formatNumber","formatRelativeTime","diffSeconds","now","abs","Math","find","u","length","round","formatList","items","filtered","filter","v","detectLanguage","I18nProvider","changeLanguage","I18nextProvider","i18n","LanguageBoundI18nProvider","useUITranslation","useTranslation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vertesia-ui-i18n.js","sources":["i18n/instance.js","i18n/rtl.js","i18n/LanguageProvider.js","i18n/useLocaleFormat.js","i18n/index.js"],"sourcesContent":["import i18next from 'i18next';\nimport { initReactI18next } from 'react-i18next';\nimport ar from './locales/ar.json';\nimport de from './locales/de.json';\nimport en from './locales/en.json';\nimport es from './locales/es.json';\nimport fr from './locales/fr.json';\nimport it from './locales/it.json';\nimport ja from './locales/ja.json';\nimport ko from './locales/ko.json';\nimport pt from './locales/pt.json';\nimport ru from './locales/ru.json';\nimport tr from './locales/tr.json';\nimport zh from './locales/zh.json';\nimport zhTW from './locales/zh-TW.json';\nexport const NAMESPACE = 'vertesia.ui';\n// Scoped instance — does NOT touch the global i18next singleton\nconst i18nInstance = i18next.createInstance();\nvoid i18nInstance.use(initReactI18next).init({\n resources: {\n ar: { [NAMESPACE]: ar },\n de: { [NAMESPACE]: de },\n en: { [NAMESPACE]: en },\n es: { [NAMESPACE]: es },\n fr: { [NAMESPACE]: fr },\n it: { [NAMESPACE]: it },\n ja: { [NAMESPACE]: ja },\n ko: { [NAMESPACE]: ko },\n pt: { [NAMESPACE]: pt },\n ru: { [NAMESPACE]: ru },\n tr: { [NAMESPACE]: tr },\n zh: { [NAMESPACE]: zh },\n 'zh-TW': { [NAMESPACE]: zhTW },\n },\n fallbackLng: 'en',\n returnEmptyString: false,\n ns: [NAMESPACE],\n defaultNS: NAMESPACE,\n interpolation: {\n escapeValue: false, // React already escapes\n },\n react: {\n useSuspense: false, // Translations are bundled, no async loading\n },\n});\nexport { i18nInstance };\n//# sourceMappingURL=instance.js.map","/**\n * RTL detection and language resolution for the @vertesia/ui locale set.\n *\n * SUPPORTED_LANGUAGES is the single source of truth for what locales the\n * switcher offers, and must stay in sync with the resources registered in\n * `./instance.ts`. A divergence-guard test (`./rtl.test.ts`) fails the build\n * if the two diverge.\n *\n * RTL_LANGUAGES is deliberately broader than SUPPORTED_LANGUAGES so that\n * dir=\"rtl\" handling is forward-compatible when new RTL locales (he, fa, ur,\n * ...) are added to instance.ts later.\n */\nexport const SUPPORTED_LANGUAGES = [\n 'ar',\n 'de',\n 'en',\n 'es',\n 'fr',\n 'it',\n 'ja',\n 'ko',\n 'pt',\n 'ru',\n 'tr',\n 'zh',\n 'zh-TW',\n];\nexport const RTL_LANGUAGES = new Set(['ar', 'he', 'fa', 'ur']);\nexport function isRTL(lng) {\n if (!lng)\n return false;\n return RTL_LANGUAGES.has(lng.split('-')[0].toLowerCase());\n}\n/**\n * Resolve any raw language code (BCP-47 or bare) to a SupportedLanguage:\n * 1. exact match against SUPPORTED_LANGUAGES (preserves `zh-TW` vs `zh`)\n * 2. base-language fallback (`pt-BR` -> `pt`)\n * 3. `'en'` fallback\n *\n * The inline FOUC script in `index.html` must reimplement this same logic\n * verbatim (it cannot import ESM before bundle load).\n */\nexport function resolveLanguage(raw) {\n if (!raw)\n return 'en';\n const list = SUPPORTED_LANGUAGES;\n if (list.includes(raw))\n return raw;\n const base = raw.split('-')[0];\n if (list.includes(base))\n return base;\n return 'en';\n}\n//# sourceMappingURL=rtl.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { DirectionProvider } from '@radix-ui/react-direction';\nimport { createContext, useContext, useEffect, useMemo, useState } from 'react';\nimport { isRTL, resolveLanguage } from './rtl.js';\nconst initialState = {\n language: 'en',\n setLanguage: () => null,\n isRTL: false,\n};\nconst LanguageProviderContext = createContext(initialState);\nexport { LanguageProviderContext };\nfunction readInitialLanguage(storageKey, defaultLanguage) {\n if (typeof window === 'undefined')\n return defaultLanguage;\n const stored = window.localStorage?.getItem(storageKey);\n if (stored)\n return resolveLanguage(stored);\n const nav = window.navigator?.language;\n if (nav)\n return resolveLanguage(nav);\n return defaultLanguage;\n}\nexport function LanguageProvider({ children, defaultLanguage = 'en', storageKey = 'vertesia-ui-language', ...props }) {\n const [language, setLanguage] = useState(() => readInitialLanguage(storageKey, defaultLanguage));\n const rtl = isRTL(language);\n useEffect(() => {\n const root = window.document.documentElement;\n root.lang = language;\n root.dir = rtl ? 'rtl' : 'ltr';\n }, [language, rtl]);\n const value = useMemo(() => ({\n language,\n isRTL: rtl,\n setLanguage: (next) => {\n window.localStorage?.setItem(storageKey, next);\n setLanguage(next);\n },\n }), [language, rtl, storageKey]);\n return (_jsx(LanguageProviderContext.Provider, { ...props, value: value, children: _jsx(DirectionProvider, { dir: rtl ? 'rtl' : 'ltr', children: children }) }));\n}\nexport function useLanguage() {\n const context = useContext(LanguageProviderContext);\n if (context === undefined) {\n throw new Error('useLanguage must be used within a LanguageProvider');\n }\n return context;\n}\n//# sourceMappingURL=LanguageProvider.js.map","import { useMemo } from 'react';\nimport { useLanguage } from './LanguageProvider.js';\nfunction toDate(input) {\n if (input == null)\n return null;\n const d = input instanceof Date ? input : new Date(input);\n return Number.isNaN(d.getTime()) ? null : d;\n}\nconst PLACEHOLDER = '—';\nconst RELATIVE_UNITS = [\n { unit: 'year', seconds: 31536000 },\n { unit: 'month', seconds: 2628000 },\n { unit: 'week', seconds: 604800 },\n { unit: 'day', seconds: 86400 },\n { unit: 'hour', seconds: 3600 },\n { unit: 'minute', seconds: 60 },\n { unit: 'second', seconds: 1 },\n];\nexport function useLocaleFormat() {\n const { language } = useLanguage();\n return useMemo(() => {\n // dateStyle: 'long' so each locale shows its native flavor — Japanese\n // gets 年月日 markers, English gets \"May 11, 2026\", Arabic gets month\n // names, etc. The 'short' style is too aggressively numeric (it\n // renders Japanese as \"2026/05/11\", which is correct per CLDR but\n // doesn't feel localized to users). Call sites that want compact\n // numeric output can pass `{ dateStyle: 'short' }` explicitly.\n const dateLong = new Intl.DateTimeFormat(language, { dateStyle: 'long' });\n const dateTimeLong = new Intl.DateTimeFormat(language, { dateStyle: 'long', timeStyle: 'short' });\n const timeShort = new Intl.DateTimeFormat(language, { timeStyle: 'short' });\n const numberDefault = new Intl.NumberFormat(language);\n const relativeDefault = new Intl.RelativeTimeFormat(language, { numeric: 'auto' });\n const listDefault = new Intl.ListFormat(language);\n return {\n language,\n formatDate: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n return options ? new Intl.DateTimeFormat(language, options).format(d) : dateLong.format(d);\n },\n formatDateTime: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n return options ? new Intl.DateTimeFormat(language, options).format(d) : dateTimeLong.format(d);\n },\n formatTime: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n return options ? new Intl.DateTimeFormat(language, options).format(d) : timeShort.format(d);\n },\n formatNumber: (value, options) => {\n if (value == null || Number.isNaN(value))\n return PLACEHOLDER;\n return options ? new Intl.NumberFormat(language, options).format(value) : numberDefault.format(value);\n },\n formatRelativeTime: (date, options) => {\n const d = toDate(date);\n if (!d)\n return PLACEHOLDER;\n const diffSeconds = (d.getTime() - Date.now()) / 1000;\n const abs = Math.abs(diffSeconds);\n const { unit, seconds } = RELATIVE_UNITS.find((u) => abs >= u.seconds) ?? RELATIVE_UNITS[RELATIVE_UNITS.length - 1];\n const value = Math.round(diffSeconds / seconds);\n const formatter = options ? new Intl.RelativeTimeFormat(language, options) : relativeDefault;\n return formatter.format(value, unit);\n },\n formatList: (items, options) => {\n const filtered = items.filter((v) => v != null && v !== '');\n if (filtered.length === 0)\n return '';\n return options ? new Intl.ListFormat(language, options).format(filtered) : listDefault.format(filtered);\n },\n };\n }, [language]);\n}\n//# sourceMappingURL=useLocaleFormat.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect } from 'react';\nimport { I18nextProvider, Trans, useTranslation } from 'react-i18next';\nimport { i18nInstance, NAMESPACE } from './instance.js';\nimport { useLanguage } from './LanguageProvider.js';\nexport { Trans };\nfunction detectLanguage(lng) {\n return lng ?? navigator.language?.split('-')[0] ?? 'en';\n}\nexport function I18nProvider({ lng, children }) {\n // Set language synchronously on first render to avoid flash of wrong language\n const language = detectLanguage(lng);\n if (i18nInstance.language !== language) {\n void i18nInstance.changeLanguage(language);\n }\n // Also react to prop changes\n useEffect(() => {\n const lang = detectLanguage(lng);\n if (i18nInstance.language !== lang) {\n void i18nInstance.changeLanguage(lang);\n }\n }, [lng]);\n return _jsx(I18nextProvider, { i18n: i18nInstance, children: children });\n}\n/**\n * Binds i18next to the language reported by the surrounding `LanguageProvider`.\n * Use this inside `VertesiaShell` (or wherever a `LanguageProvider` ancestor is\n * available) so language changes propagate to all `useUITranslation()` callers\n * without a static `lng` prop.\n */\nexport function LanguageBoundI18nProvider({ children }) {\n const { language } = useLanguage();\n return _jsx(I18nProvider, { lng: language, children: children });\n}\n/**\n * Hook for components inside @vertesia/ui to get translation functions.\n * Always binds to the 'vertesia.ui' namespace on the scoped instance.\n */\nexport function useUITranslation() {\n return useTranslation(NAMESPACE, { i18n: i18nInstance });\n}\nexport { i18nInstance, NAMESPACE } from './instance.js';\nexport { LanguageProvider, LanguageProviderContext, useLanguage, } from './LanguageProvider.js';\nexport { isRTL, RTL_LANGUAGES, resolveLanguage, SUPPORTED_LANGUAGES, } from './rtl.js';\nexport { useLocaleFormat } from './useLocaleFormat.js';\n//# sourceMappingURL=index.js.map"],"names":["NAMESPACE","i18nInstance","i18next","createInstance","use","initReactI18next","init","resources","ar","de","en","es","fr","it","ja","ko","pt","ru","tr","zh","fallbackLng","returnEmptyString","ns","defaultNS","interpolation","escapeValue","react","useSuspense","SUPPORTED_LANGUAGES","RTL_LANGUAGES","Set","isRTL","lng","has","split","toLowerCase","resolveLanguage","raw","list","includes","base","LanguageProviderContext","createContext","language","setLanguage","LanguageProvider","children","defaultLanguage","storageKey","props","useState","window","stored","localStorage","getItem","nav","navigator","readInitialLanguage","rtl","useEffect","root","document","documentElement","lang","dir","value","useMemo","next","setItem","_jsx","Provider","DirectionProvider","useLanguage","context","useContext","undefined","Error","toDate","input","d","Date","Number","isNaN","getTime","PLACEHOLDER","RELATIVE_UNITS","unit","seconds","useLocaleFormat","dateLong","Intl","DateTimeFormat","dateStyle","dateTimeLong","timeStyle","timeShort","numberDefault","NumberFormat","relativeDefault","RelativeTimeFormat","numeric","listDefault","ListFormat","formatDate","date","options","format","formatDateTime","formatTime","formatNumber","formatRelativeTime","diffSeconds","now","abs","Math","find","u","length","round","formatList","items","filtered","filter","v","detectLanguage","I18nProvider","changeLanguage","I18nextProvider","i18n","LanguageBoundI18nProvider","useUITranslation","useTranslation"],"mappings":"wVAeY,MAACA,EAAY,cAEnBC,EAAeC,EAAQC,iBACxBF,EAAaG,IAAIC,GAAkBC,KAAK,CACzCC,UAAW,CACPC,GAAI,CAAER,CAACA,8/pCACPS,GAAI,CAAET,CAACA,gyxCACPU,GAAI,CAAEV,CAACA,+spCACPW,GAAI,CAAEX,CAACA,4yxCACPY,GAAI,CAAEZ,CAACA,spzCACPa,GAAI,CAAEb,CAACA,ozxCACPc,GAAI,CAAEd,CAACA,4r7BACPe,GAAI,CAAEf,CAACA,s35BACPgB,GAAI,CAAEhB,CAACA,qqwCACPiB,GAAI,CAAEjB,CAACA,+0vCACPkB,GAAI,CAAElB,CAACA,6/qCACPmB,GAAI,CAAEnB,CAACA,wszBACP,QAAS,CAAEA,CAACA,8vzBAEhBoB,YAAa,KACbC,mBAAmB,EACnBC,GAAI,CAACtB,GACLuB,UAAWvB,EACXwB,cAAe,CACXC,aAAa,GAEjBC,MAAO,CACHC,aAAa,KC9BT,MAACC,EAAsB,CAC/B,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,SAESC,EAAgB,IAAIC,IAAI,CAAC,KAAM,KAAM,KAAM,OACjD,SAASC,EAAMC,GAClB,QAAKA,GAEEH,EAAcI,IAAID,EAAIE,MAAM,KAAK,GAAGC,cAC/C,CAUO,SAASC,EAAgBC,GAC5B,IAAKA,EACD,MAAO,KACX,MAAMC,EAAOV,EACb,GAAIU,EAAKC,SAASF,GACd,OAAOA,EACX,MAAMG,EAAOH,EAAIH,MAAM,KAAK,GAC5B,OAAII,EAAKC,SAASC,GACPA,EACJ,IACX,CChDA,MAKMC,EAA0BC,EALX,CACjBC,SAAU,KACVC,YAAa,IAAM,KACnBb,OAAO,IAeJ,SAASc,GAAiBC,SAAEA,EAAQC,gBAAEA,EAAkB,KAAIC,WAAEA,EAAa,0BAA2BC,IACzG,MAAON,EAAUC,GAAeM,EAAS,IAZ7C,SAA6BF,EAAYD,GACrC,GAAsB,oBAAXI,OACP,OAAOJ,EACX,MAAMK,EAASD,OAAOE,cAAcC,QAAQN,GAC5C,GAAII,EACA,OAAOhB,EAAgBgB,GAC3B,MAAMG,EAAMJ,OAAOK,WAAWb,SAC9B,OAAIY,EACOnB,EAAgBmB,GACpBR,CACX,CAEmDU,CAAoBT,EAAYD,IACzEW,EAAM3B,EAAMY,GAClBgB,EAAU,KACN,MAAMC,EAAOT,OAAOU,SAASC,gBAC7BF,EAAKG,KAAOpB,EACZiB,EAAKI,IAAMN,EAAM,MAAQ,OAC1B,CAACf,EAAUe,IACd,MAAMO,EAAQC,EAAQ,KAAA,CAClBvB,WACAZ,MAAO2B,EACPd,YAAcuB,IACVhB,OAAOE,cAAce,QAAQpB,EAAYmB,GACzCvB,EAAYuB,MAEhB,CAACxB,EAAUe,EAAKV,IACpB,OAAQqB,EAAK5B,EAAwB6B,SAAU,IAAKrB,EAAOgB,MAAOA,EAAOnB,SAAUuB,EAAKE,EAAmB,CAAEP,IAAKN,EAAM,MAAQ,MAAOZ,SAAUA,KACrJ,CACO,SAAS0B,IACZ,MAAMC,EAAUC,EAAWjC,GAC3B,QAAgBkC,IAAZF,EACA,MAAM,IAAIG,MAAM,sDAEpB,OAAOH,CACX,CC5CA,SAASI,EAAOC,GACZ,GAAa,MAATA,EACA,OAAO,KACX,MAAMC,EAAID,aAAiBE,KAAOF,EAAQ,IAAIE,KAAKF,GACnD,OAAOG,OAAOC,MAAMH,EAAEI,WAAa,KAAOJ,CAC9C,CACA,MAAMK,EAAc,IACdC,EAAiB,CACnB,CAAEC,KAAM,OAAQC,QAAS,SACzB,CAAED,KAAM,QAASC,QAAS,QAC1B,CAAED,KAAM,OAAQC,QAAS,QACzB,CAAED,KAAM,MAAOC,QAAS,OACxB,CAAED,KAAM,OAAQC,QAAS,MACzB,CAAED,KAAM,SAAUC,QAAS,IAC3B,CAAED,KAAM,SAAUC,QAAS,IAExB,SAASC,IACZ,MAAM7C,SAAEA,GAAa6B,IACrB,OAAON,EAAQ,KAOX,MAAMuB,EAAW,IAAIC,KAAKC,eAAehD,EAAU,CAAEiD,UAAW,SAC1DC,EAAe,IAAIH,KAAKC,eAAehD,EAAU,CAAEiD,UAAW,OAAQE,UAAW,UACjFC,EAAY,IAAIL,KAAKC,eAAehD,EAAU,CAAEmD,UAAW,UAC3DE,EAAgB,IAAIN,KAAKO,aAAatD,GACtCuD,EAAkB,IAAIR,KAAKS,mBAAmBxD,EAAU,CAAEyD,QAAS,SACnEC,EAAc,IAAIX,KAAKY,WAAW3D,GACxC,MAAO,CACHA,WACA4D,WAAY,CAACC,EAAMC,KACf,MAAM1B,EAAIF,EAAO2B,GACjB,OAAKzB,EAEE0B,EAAU,IAAIf,KAAKC,eAAehD,EAAU8D,GAASC,OAAO3B,GAAKU,EAASiB,OAAO3B,GAD7EK,GAGfuB,eAAgB,CAACH,EAAMC,KACnB,MAAM1B,EAAIF,EAAO2B,GACjB,OAAKzB,EAEE0B,EAAU,IAAIf,KAAKC,eAAehD,EAAU8D,GAASC,OAAO3B,GAAKc,EAAaa,OAAO3B,GADjFK,GAGfwB,WAAY,CAACJ,EAAMC,KACf,MAAM1B,EAAIF,EAAO2B,GACjB,OAAKzB,EAEE0B,EAAU,IAAIf,KAAKC,eAAehD,EAAU8D,GAASC,OAAO3B,GAAKgB,EAAUW,OAAO3B,GAD9EK,GAGfyB,aAAc,CAAC5C,EAAOwC,IACL,MAATxC,GAAiBgB,OAAOC,MAAMjB,GACvBmB,EACJqB,EAAU,IAAIf,KAAKO,aAAatD,EAAU8D,GAASC,OAAOzC,GAAS+B,EAAcU,OAAOzC,GAEnG6C,mBAAoB,CAACN,EAAMC,KACvB,MAAM1B,EAAIF,EAAO2B,GACjB,IAAKzB,EACD,OAAOK,EACX,MAAM2B,GAAehC,EAAEI,UAAYH,KAAKgC,OAAS,IAC3CC,EAAMC,KAAKD,IAAIF,IACfzB,KAAEA,EAAIC,QAAEA,GAAYF,EAAe8B,KAAMC,GAAMH,GAAOG,EAAE7B,UAAYF,EAAeA,EAAegC,OAAS,GAC3GpD,EAAQiD,KAAKI,MAAMP,EAAcxB,GAEvC,OADkBkB,EAAU,IAAIf,KAAKS,mBAAmBxD,EAAU8D,GAAWP,GAC5DQ,OAAOzC,EAAOqB,IAEnCiC,WAAY,CAACC,EAAOf,KAChB,MAAMgB,EAAWD,EAAME,OAAQC,GAAW,MAALA,GAAmB,KAANA,GAClD,OAAwB,IAApBF,EAASJ,OACF,GACJZ,EAAU,IAAIf,KAAKY,WAAW3D,EAAU8D,GAASC,OAAOe,GAAYpB,EAAYK,OAAOe,MAGvG,CAAC9E,GACR,CCvEA,SAASiF,EAAe5F,GACpB,OAAOA,GAAOwB,UAAUb,UAAUT,MAAM,KAAK,IAAM,IACvD,CACO,SAAS2F,GAAa7F,IAAEA,EAAGc,SAAEA,IAEhC,MAAMH,EAAWiF,EAAe5F,GAWhC,OAVI/B,EAAa0C,WAAaA,GACrB1C,EAAa6H,eAAenF,GAGrCgB,EAAU,KACN,MAAMI,EAAO6D,EAAe5F,GACxB/B,EAAa0C,WAAaoB,GACrB9D,EAAa6H,eAAe/D,IAEtC,CAAC/B,IACGqC,EAAK0D,EAAiB,CAAEC,KAAM/H,EAAc6C,SAAUA,GACjE,CAOO,SAASmF,GAA0BnF,SAAEA,IACxC,MAAMH,SAAEA,GAAa6B,IACrB,OAAOH,EAAKwD,EAAc,CAAE7F,IAAKW,EAAUG,SAAUA,GACzD,CAKO,SAASoF,IACZ,OAAOC,EAAenI,EAAW,CAAEgI,KAAM/H,GAC7C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Env as e}from"@vertesia/ui/env";import{jwtDecode as t}from"jwt-decode";import{getAnalytics as o,logEvent as n}from"firebase/analytics";import{initializeApp as r}from"firebase/app";import{getAuth as i,onAuthStateChanged as a}from"firebase/auth";import{useCallback as s,createContext as c,useContext as l,useState as u,useEffect as d,useRef as h}from"react";import{i18nInstance as g,NAMESPACE as f}from"@vertesia/ui/i18n";import{VertesiaClient as p}from"@vertesia/client";import{jsx as m}from"react/jsx-runtime";const w="composableai.lastSelectedAccountId",v="composableai.lastSelectedProjectId";let k,S,T=null,b=null,_=null;function y(){if(!T)try{if(!e.firebase)throw new Error("Firebase configuration is not available in the environment");T=r(e.firebase)}catch(e){throw console.error("Failed to initialize Firebase app:",e),new Error("Firebase initialization failed - environment may not be properly initialized",{cause:e})}return T}function j(){return b||(b=o(y())),b}function I(){return _||(_=i(y())),_}async function $(t){if(t)if(e.firebase)try{t&&console.log(`Resolving tenant ID from email: ${t}`);let o=3,n=250;for(;o>0;)try{const o=await fetch("/api/resolve-tenant",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tenantEmail:t}),signal:AbortSignal.timeout(5e3)});if(!o)throw new Error("No response received from tenant API");if(!o.ok){try{const e=await o.json();console.error("Failed to resolve tenant ID:",e.error)}catch{console.error(`Failed to resolve tenant ID: HTTP ${o.status}`)}if(404===o.status)return void console.warn(`Tenant not found for ${t}`);throw new Error(`HTTP error ${o.status}`)}const n=await o.json();if(n?.firebaseTenantId){const t=I();return t.tenantId=n.firebaseTenantId,e.firebase.providerType=n.provider??"oidc",console.log(`Tenant ID set to ${t.tenantId}`),n}return void console.error(`Invalid response format, missing tenantId for ${t}`)}catch(e){if(!(o>1))throw e;console.warn(`Tenant resolution failed, retrying in ${n}ms...`,e),await new Promise(e=>setTimeout(e,n)),n*=2,o--}}catch(e){console.error("Error setting Firebase tenant:",e instanceof Error?e.message:"Unknown error")}else console.log("Firebase configuration is not available in the environment");else console.log("No tenant name or email specified, skipping tenant setup")}async function E(t){const o=I().currentUser;return o?o.getIdToken(t).then(n=>(e.logger.info("Got Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:t}}),n)).catch(n=>(e.logger.error("Failed to get Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:t,error:n}}),console.error("Failed to get access token",n),null)):(e.logger.warn("No user found"),Promise.resolve(null))}function A(e){return e?.replace(/\/+$/,"")}function F(e){return t(e)}async function U(o,n,r,i,a=0){console.log(`Getting/refreshing composable token for account ${n} and project ${r} `),e.logger.info("Getting/refreshing composable token",{vertesia:{account_id:n,project_id:r,retry_count:a}});const s=await o();if(!s)throw console.log("No id token found - using cookie auth"),new Error("No id token found");const c=e.endpoints.sts;console.log("Using STS for token generation:",c),e.logger.info("Using STS for token generation",{vertesia:{account_id:n,project_id:r,sts_url:c}});try{const l=new URL(`${c}/token/issue`),u={type:"user",account_id:n,project_id:r,expires_at:i?Math.floor(Date.now()/1e3)+i:void 0},d=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(u)}).catch(t=>{throw console.error("Failed to call STS endpoint",t),e.logger.error("Failed to call STS endpoint",{vertesia:{account_id:n,project_id:r,error:t}}),new O("Failed to call STS endpoint",c)});if(s&&404===d?.status){console.log("404: User not found - calling ensure-user endpoint"),e.logger.info("404: User not found - calling ensure-user endpoint",{vertesia:{account_id:n,project_id:r,status:d?.status}});const c=await fetch(`${e.endpoints.studio}/auth/ensure-user`,{method:"POST",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"}});if(412===c.status){console.log("412: No invite found - signup required"),e.logger.info("412: No invite found - signup required",{vertesia:{account_id:n,project_id:r}});const o=t(s);if(!o?.email)throw e.logger.error("No email found in id token"),new Error("No email found in id token");throw new x("User not found - signup required",o.email)}if(403===c.status)throw e.logger.warn("403: Customer-domain user requires an invite to join",{vertesia:{account_id:n,project_id:r}}),new Error("Customer-domain user requires an invite to join");if(!c.ok)throw console.error("Failed to ensure user exists",c.status),e.logger.error("Failed to ensure user exists",{vertesia:{account_id:n,project_id:r,status:c.status}}),new Error("Failed to ensure user exists");return console.log("User ensured - retrying token generation"),e.logger.info("User ensured - retrying token generation",{vertesia:{account_id:n,project_id:r}}),U(o,n,r,i,a)}if(s&&412===d?.status){console.log("412: auth succeeded but user doesn't exist - signup required",d?.status),e.logger.error("412: auth succeeded but user doesn't exist - signup required",{vertesia:{account_id:n,project_id:r,status:d?.status}});const o=t(s);if(!o?.email)throw e.logger.error("No email found in id token"),new Error("No email found in id token");throw e.logger.error("User not found",{vertesia:{account_id:n,project_id:r,email:o.email}}),new x("User not found",o.email)}if(403===d.status){if(a>0)throw console.error("403: Access denied even without account scope - user may have no accounts"),e.logger.error("403: Access denied after retry - authorization failure",{vertesia:{account_id:n,project_id:r,status:d.status,retry_count:a}}),new Error("Access denied - user may not have access to any accounts");return console.log("403: Access denied - clearing cached account and retrying without account scope"),e.logger.warn("403: Access denied - clearing cached account and retrying",{vertesia:{account_id:n,project_id:r,status:d.status,retry_count:a}}),localStorage.removeItem(w),n&&localStorage.removeItem(`${v}-${n}`),U(o,void 0,void 0,i,a+1)}if(!d.ok){const t=await d.text();throw console.error("STS token generation failed:",d.status,t),e.logger.error("STS token generation failed",{vertesia:{status:d.status,error:t,account_id:n,project_id:r}}),new Error(`Failed to get token from STS: ${d.status}`)}const{token:h}=await d.json();return console.log("Successfully got token from STS"),e.logger.info("Successfully got token from STS"),h}catch(t){if(t instanceof x||t instanceof O)throw t;throw localStorage.removeItem(w),n&&localStorage.removeItem(`${v}-${n}`),console.error("Failed to get composable token from STS",t),e.logger.error("Failed to get composable token from STS",{vertesia:{account_id:n,project_id:r,error:t}}),new Error("Failed to get composable token",{cause:t})}}async function P(e,t,o){return U(E,e,t,o)}async function L(e,t,o,n){return U(()=>Promise.resolve(e),t,o,n)}function C(){return k}async function N(t,o,n,r=!1,i=!1){const a=t??localStorage.getItem(w)??void 0,s=o??localStorage.getItem(`${v}-${a}`)??void 0,c=e.isLocalDev?e.devAuthToken:void 0,l=c??n??k;if(!r&&k&&S&&S.exp>Date.now()/1e3+300)return{rawToken:k,token:S,error:!1};if(!r&&function(t){if(!t)return!1;try{return A(F(t).iss)===A(e.endpoints.sts)}catch{return!1}}(l)){if(k=l,S=F(k),!S.exp)throw new Error("Invalid composable token");return{rawToken:k,token:S,error:!1}}if(c||i||!I().currentUser?c||!n&&!k?c&&(k=c):k=await U(()=>Promise.resolve(n??k),a,s):k=await P(a,s),!k)throw e.logger.error("Cannot acquire a composable token",{vertesia:{account_id:a,project_id:s}}),new Error("Cannot acquire a composable token");if(S=F(k),!S?.exp||!k)throw console.error("Invalid composable token",S),e.logger.error("Invalid composable token",{vertesia:{account_id:a,project_id:s}}),new Error("Invalid composable token");return{rawToken:k,token:S,error:!1}}class x extends Error{email;constructor(e,t){super(e),this.name="UserNotFoundError",this.email=t}}class O extends Error{stsURL;constructor(e,t){super(e),this.name="STSError",this.stsURL=t}}const D="auth_state",R="auth_state_expiry";function z(){return{generateState:s(()=>{const e=crypto.randomUUID(),t=Date.now()+3e5;return sessionStorage.setItem(D,e),sessionStorage.setItem(R,t.toString()),e},[]),verifyState:s(e=>{if(!e)return"Missing state";const t=sessionStorage.getItem(D),o=parseInt(sessionStorage.getItem(R)||"0",10);let n;return n=t!==e?`State mismatched (${t} !== ${e})`:Date.now()>o?"State expired":void 0,n},[]),clearState:s(()=>{sessionStorage.removeItem(D),sessionStorage.removeItem(R)},[])}}function q(e){return!("firebase"===window.AUTH_MODE)}class H{isLoading=!0;client;authError;authToken;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(t,o){this.client=t||new p({serverUrl:e.endpoints.studio,storeUrl:e.endpoints.zeno,tokenServerUrl:e.endpoints.sts}),o&&(this.setSession=o),this.logout=this.logout.bind(this)}get store(){return this.client.store}get user(){return this.authToken}get account(){return this.authToken?.account}get project(){return this.authToken?.project}get accounts(){return this.authToken?.accounts}get authCallback(){return this.rawAuthToken.then(e=>`Bearer ${e}`)}get rawAuthToken(){return N().then(e=>{const o=e?.rawToken;if(!o)throw new Error("No token available");return this.authToken=t(o),o})}async refreshAuthToken(){const e=await N(void 0,void 0,void 0,!0),o=e?.rawToken;if(!o)throw new Error("No token available");return this.authToken=t(o),this.setSession?.(this.clone()),this.authToken}signOut(){this.logout()}getAccount(){return this.authToken?.account}async login(o,n={}){return this.authError=void 0,this.isLoading=!1,this.client.withAuthCallback(()=>this.authCallback),this.authToken=t(o),console.log(`Logging in as ${this.authToken?.name} with account ${this.authToken?.account.name} (${this.authToken?.account.id}, and project ${this.authToken?.project?.name} (${this.authToken?.project?.id})`),localStorage.setItem(w,this.authToken.account.id),localStorage.setItem(`${v}-${this.authToken.account.id}`,this.authToken.project?.id??""),e.onLogin?.(this.authToken),(n.loadOnboardingStatus??1)&&await this.fetchOnboardingStatus(),Promise.resolve()}isLoggedIn(){return!!this.authToken}logout(){if(console.log("Logging out"),q()){console.log("Using central auth logout"),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0);const e=new URL("https://internal-auth.vertesia.app/"),t=new URL(window.location.href);t.hash="",e.pathname="/logout",e.searchParams.set("redirect_uri",t.toString()),location.replace(e.toString())}else{console.log("Using Firebase logout");const e=!!this.authToken;this.authToken&&I().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0),e&&location.replace("/")}}async switchAccount(e){localStorage.setItem(w,e),this&&(this.account&&this.project?localStorage.setItem(`${v}-${this.account.id}`,this.project.id):this.account&&localStorage.removeItem(`${v}-${this.account.id}`)),window.location.replace(`/?a=${e}`)}async switchProject(e){this.account&&localStorage.setItem(`${v}-${this.account.id}`,e),window.location.replace(`/?a=${this.account?.id}&p=${e}`)}async fetchAccounts(){return this.client.accounts.list().then(e=>{if(!this.authToken)throw new Error("No token available");this.authToken.accounts=e,this.setSession?.(this.clone())}).catch(e=>{throw console.error("Failed to fetch accounts",e),e})}async fetchProjects(e){return this.client.projects.list([e]).then(t=>{if(!this.authToken)throw new Error("No token available");this.authToken={...this.authToken,accounts:this.authToken.accounts?.map(o=>o.id===e?{...o,projects:t.filter(t=>t.account===e)}:o)},this.setSession?.(this.clone())}).catch(e=>{throw console.error("Failed to fetch projects",e),e})}async fetchOnboardingStatus(){if(this.onboardingComplete)return console.log("Onboarding already completed"),!1;const e=this.onboardingComplete;try{const t=await this.client.account.onboardingProgress();if(this.onboardingComplete=Object.values(t).every(e=>!0===e),e!==this.onboardingComplete)return!0;this.setSession?.(this.clone())}catch(e){console.error("Error fetching onboarding status:",e),this.onboardingComplete=!1,this.setSession?.(this.clone())}return!1}clone(){const e=new H(this.client);return e.isLoading=this.isLoading,e.authError=this.authError,e.authToken=this.authToken,e.setSession=this.setSession,e.lastSelectedAccount=this.lastSelectedAccount,e.switchAccount=this.switchAccount,e.onboardingComplete=this.onboardingComplete,e}}const B=c(void 0);function G(){const e=l(B);if(!e)throw new Error("useUserSession must be used within a UserSessionProvider");return e}function J(){const{user:e}=G(),[t,o]=u(null),[n,r]=u(!0),[i,a]=u(null);return d(()=>{(async()=>{if(!e?.email)return o(null),void r(!1);try{const t=await fetch("/api/resolve-tenant",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tenantEmail:e.email})});if(t.ok){const e=await t.json();o(e?{tenantKey:e.name||"unknown",name:e.label||e.name||"Unknown",domain:e.domain||[],firebaseTenantId:e.firebaseTenantId,provider:e.provider,logo:e.logo}:null)}else o(null)}catch(e){console.error("Error loading current tenant:",e),a(g.getFixedT(null,f)("errors.failedToLoadTenantConfig")),o(null)}finally{r(!1)}})()},[e?.email]),{currentTenant:t,isLoading:n,error:i}}function M({children:t,loadOnboardingStatus:o=!0}){const n=new URLSearchParams(location.hash.substring(1)),r=n.get("token"),i=n.get("state"),[s,c]=u(new H),{generateState:l,verifyState:g,clearState:f}=z(),p=h(!1),k=h(void 0),S=(t,o)=>{const n=new URL(`https://internal-auth.vertesia.app/?sts=${e.endpoints.sts??"https://sts.vertesia.io"}`),r=new URL(window.location.href);r.hash="",n.searchParams.set("redirect_uri",r.toString()),n.searchParams.set("state",l()),location.replace(n.toString())};return k.current=()=>{if(p.current)return void console.log("Auth: skipping duplicate auth flow initiation");p.current=!0,console.log("Auth: starting auth flow"),e.logger.info("Starting auth flow");const t=new URL(window.location.href),n=t.searchParams.get("a")??localStorage.getItem(w)??void 0,l=t.searchParams.get("p")??localStorage.getItem(`${v}-${n}`)??void 0;if(console.log("Auth: selected account",n),console.log("Auth: selected project",l),e.logger.info("Selected account and project",{vertesia:{account_id:n,project_id:l}}),e.isLocalDev&&e.devAuthToken)return s.setSession=c,void N(n,l,e.devAuthToken).then(e=>{s.login(e.rawToken).then(()=>c(s.clone()))}).catch(t=>{console.error("Failed to initialize dev auth token",t),e.logger.error("Failed to initialize dev auth token",{vertesia:{account_id:n,project_id:l,error:t}}),s.isLoading=!1,s.authError=t instanceof Error?t:new Error(String(t)),c(s.clone())});if(r&&i){s.setSession=c;const t=g(i);return t?(console.error(`Auth: invalid state: ${t}`),e.logger.error(`Invalid state: ${t}`,{vertesia:{state:i}}),S()):f(),void N(n,l,r,!1,q()).then(e=>{s.login(e.rawToken,{loadOnboardingStatus:o}).then(()=>{c(s.clone()),window.location.hash=""})}).catch(t=>t instanceof x?(console.log("User not found - will trigger signup flow",t),s.isLoading=!1,s.authError=t,void c(s.clone())):t instanceof O?(console.error("STS error during token exchange",t),e.logger.error("STS error during token exchange",{vertesia:{account_id:n,project_id:l,sts_url:t.stsURL,error:t}}),window.alert("Authentication failed due to an issue with the authentication service. Please try again later."),s.logout(),c(s.clone()),void(window.location.hash="")):(console.error("Failed to fetch user token from studio, redirecting to central auth",t),e.logger.error("Failed to fetch user token from studio, redirecting to central auth",{vertesia:{error:t}}),void S()))}let u,d=!1;const h=()=>{if(!d){if(!s.isLoggedIn()){if(console.log("Auth: not logged in & no token/state"),e.logger.info("Not logged in & no token/state",{vertesia:{account_id:n,project_id:l}}),q())return console.log("Auth: host is not in Firebase auth allowlist, redirecting to central auth with selection",n,l),e.logger.info("Redirecting to central auth with selection",{vertesia:{account_id:n,project_id:l}}),void S();console.log("Auth: host is in Firebase auth allowlist"),e.logger.info("Host is in Firebase auth allowlist",{vertesia:{account_id:n,project_id:l}})}u=a(I(),async t=>{t?(console.log("Auth: successful login with firebase"),e.logger.info("Successful login with firebase",{vertesia:{account_id:n,project_id:l}}),s.setSession=c,await N(n,l,void 0,!1,q()).then(e=>{s.login(e.rawToken,{loadOnboardingStatus:o}).then(()=>c(s.clone()))}).catch(t=>{console.error("Failed to fetch user token from studio",t),e.logger.error("Failed to fetch user token from studio",{vertesia:{account_id:n,project_id:l,error:t}}),t instanceof x||s.logout(),s.isLoading=!1,s.authError=t,c(s.clone())})):(console.log("Auth: using anonymous user"),e.logger.info("Using anonymous user",{vertesia:{account_id:n,project_id:l}}),s.client.withAuthCallback(void 0),s.logout(),c(s.clone()))})}};return e.authTokenProvider?(s.setSession=c,e.authTokenProvider().then(async e=>{if(!e)return void h();const t=await N(n,l,e,!1,q());await s.login(t.rawToken,{loadOnboardingStatus:o}),d||c(s.clone())}).catch(t=>{console.warn("Auth: failed to initialize injected auth token",t),e.logger.warn("Failed to initialize injected auth token",{vertesia:{account_id:n,project_id:l,error:t}}),h()}),()=>{d=!0,u?.()}):(h(),()=>{d=!0,u?.()})},d(()=>k.current?.(),[]),m(B.Provider,{value:s,children:t})}function K(){return{tagUserSession:async e=>{const t=window.localStorage.getItem("composableSignupData");e?t&&window.localStorage.removeItem("composableSignupData"):console.error("No user found -- skipping tagging")},trackEvent:(t,o)=>{e.isProd||console.debug("track event",t,o),n(j(),t,{...o,debug_mode:!e.isProd})}}}export{w as LastSelectedAccountId_KEY,v as LastSelectedProjectId_KEY,O as STSError,x as UserNotFoundError,H as UserSession,B as UserSessionContext,M as UserSessionProvider,U as fetchComposableToken,P as fetchComposableTokenFromFirebaseToken,L as fetchComposableTokenFromVertesiaToken,N as getComposableToken,C as getCurrentVertesiaToken,j as getFirebaseAnalytics,y as getFirebaseApp,I as getFirebaseAuth,E as getFirebaseAuthToken,$ as setFirebaseTenant,z as useAuthState,J as useCurrentTenant,K as useUXTracking,G as useUserSession};
|
|
1
|
+
import{Env as e}from"@vertesia/ui/env";import{jwtDecode as t}from"jwt-decode";import{getAnalytics as o,logEvent as r}from"firebase/analytics";import{initializeApp as n}from"firebase/app";import{getAuth as i,onAuthStateChanged as s}from"firebase/auth";import{useCallback as a,createContext as c,useContext as l,useState as u,useEffect as d,useRef as h}from"react";import{i18nInstance as g,NAMESPACE as f}from"@vertesia/ui/i18n";import{VertesiaClient as m}from"@vertesia/client";import{jsx as p}from"react/jsx-runtime";const w="composableai.lastSelectedAccountId",v="composableai.lastSelectedProjectId";let S,k,b=null,T=null,_=null;function y(){if(!b)try{if(!e.firebase)throw new Error("Firebase configuration is not available in the environment");b=n(e.firebase)}catch(e){throw console.error("Failed to initialize Firebase app:",e),new Error("Firebase initialization failed - environment may not be properly initialized",{cause:e})}return b}function j(){return T||(T=o(y())),T}function I(){return _||(_=i(y())),_}async function $(t){if(t)if(e.firebase)try{t&&console.log(`Resolving tenant ID from email: ${t}`);let o=3,r=250;for(;o>0;)try{const o=await fetch("/api/resolve-tenant",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tenantEmail:t}),signal:AbortSignal.timeout(5e3)});if(!o)throw new Error("No response received from tenant API");if(!o.ok){try{const e=await o.json();console.error("Failed to resolve tenant ID:",e.error)}catch{console.error(`Failed to resolve tenant ID: HTTP ${o.status}`)}if(404===o.status)return void console.warn(`Tenant not found for ${t}`);throw new Error(`HTTP error ${o.status}`)}const r=await o.json();if(r?.firebaseTenantId){const t=I();return t.tenantId=r.firebaseTenantId,e.firebase.providerType=r.provider??"oidc",console.log(`Tenant ID set to ${t.tenantId}`),r}return void console.error(`Invalid response format, missing tenantId for ${t}`)}catch(e){if(!(o>1))throw e;console.warn(`Tenant resolution failed, retrying in ${r}ms...`,e),await new Promise(e=>setTimeout(e,r)),r*=2,o--}}catch(e){console.error("Error setting Firebase tenant:",e instanceof Error?e.message:"Unknown error")}else console.log("Firebase configuration is not available in the environment");else console.log("No tenant name or email specified, skipping tenant setup")}async function E(t){const o=I().currentUser;return o?o.getIdToken(t).then(r=>(e.logger.info("Got Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:t}}),r)).catch(r=>(e.logger.error("Failed to get Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:t,error:r}}),console.error("Failed to get access token",r),null)):(e.logger.warn("No user found"),Promise.resolve(null))}async function U(o,r,n,i,s=0){console.log(`Getting/refreshing composable token for account ${r} and project ${n} `),e.logger.info("Getting/refreshing composable token",{vertesia:{account_id:r,project_id:n,retry_count:s}});const a=await o();if(!a)throw console.log("No id token found - using cookie auth"),new Error("No id token found");const c=e.endpoints.sts;console.log("Using STS for token generation:",c),e.logger.info("Using STS for token generation",{vertesia:{account_id:r,project_id:n,sts_url:c}});try{const l=new URL(`${c}/token/issue`),u={type:"user",account_id:r,project_id:n,expires_at:i?Math.floor(Date.now()/1e3)+i:void 0},d=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a}`},body:JSON.stringify(u)}).catch(t=>{throw console.error("Failed to call STS endpoint",t),e.logger.error("Failed to call STS endpoint",{vertesia:{account_id:r,project_id:n,error:t}}),new N("Failed to call STS endpoint",c)});if(a&&404===d?.status){console.log("404: User not found - calling ensure-user endpoint"),e.logger.info("404: User not found - calling ensure-user endpoint",{vertesia:{account_id:r,project_id:n,status:d?.status}});const c=await fetch(`${e.endpoints.studio}/auth/ensure-user`,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"}});if(412===c.status){console.log("412: No invite found - signup required"),e.logger.info("412: No invite found - signup required",{vertesia:{account_id:r,project_id:n}});const o=t(a);if(!o?.email)throw e.logger.error("No email found in id token"),new Error("No email found in id token");throw new C("User not found - signup required",o.email)}if(403===c.status)throw e.logger.warn("403: Customer-domain user requires an invite to join",{vertesia:{account_id:r,project_id:n}}),new Error("Customer-domain user requires an invite to join");if(!c.ok)throw console.error("Failed to ensure user exists",c.status),e.logger.error("Failed to ensure user exists",{vertesia:{account_id:r,project_id:n,status:c.status}}),new Error("Failed to ensure user exists");return console.log("User ensured - retrying token generation"),e.logger.info("User ensured - retrying token generation",{vertesia:{account_id:r,project_id:n}}),U(o,r,n,i,s)}if(a&&412===d?.status){console.log("412: auth succeeded but user doesn't exist - signup required",d?.status),e.logger.error("412: auth succeeded but user doesn't exist - signup required",{vertesia:{account_id:r,project_id:n,status:d?.status}});const o=t(a);if(!o?.email)throw e.logger.error("No email found in id token"),new Error("No email found in id token");throw e.logger.error("User not found",{vertesia:{account_id:r,project_id:n,email:o.email}}),new C("User not found",o.email)}if(403===d.status){if(s>0)throw console.error("403: Access denied even without account scope - user may have no accounts"),e.logger.error("403: Access denied after retry - authorization failure",{vertesia:{account_id:r,project_id:n,status:d.status,retry_count:s}}),new Error("Access denied - user may not have access to any accounts");return console.log("403: Access denied - clearing cached account and retrying without account scope"),e.logger.warn("403: Access denied - clearing cached account and retrying",{vertesia:{account_id:r,project_id:n,status:d.status,retry_count:s}}),localStorage.removeItem(w),r&&localStorage.removeItem(`${v}-${r}`),U(o,void 0,void 0,i,s+1)}if(!d.ok){const t=await d.text();throw console.error("STS token generation failed:",d.status,t),e.logger.error("STS token generation failed",{vertesia:{status:d.status,error:t,account_id:r,project_id:n}}),new Error(`Failed to get token from STS: ${d.status}`)}const{token:h}=await d.json();return console.log("Successfully got token from STS"),e.logger.info("Successfully got token from STS"),h}catch(t){if(t instanceof C||t instanceof N)throw t;throw localStorage.removeItem(w),r&&localStorage.removeItem(`${v}-${r}`),console.error("Failed to get composable token from STS",t),e.logger.error("Failed to get composable token from STS",{vertesia:{account_id:r,project_id:n,error:t}}),new Error("Failed to get composable token",{cause:t})}}async function A(e,t,o){return U(E,e,t,o)}async function F(e,t,o,r){return U(()=>Promise.resolve(e),t,o,r)}function P(){return S}async function L(o,r,n,i=!1,s=!1){const a=o??localStorage.getItem(w)??void 0,c=r??localStorage.getItem(`${v}-${a}`)??void 0;if(!i&&S&&k&&k.exp>Date.now()/1e3+300)return{rawToken:S,token:k,error:!1};if(!s&&I().currentUser?S=await A(a,c):(n||S)&&(S=await U(()=>Promise.resolve(n??S),a,c)),!S)throw e.logger.error("Cannot acquire a composable token",{vertesia:{account_id:a,project_id:c}}),new Error("Cannot acquire a composable token");if(k=t(S),!k?.exp||!S)throw console.error("Invalid composable token",k),e.logger.error("Invalid composable token",{vertesia:{account_id:a,project_id:c}}),new Error("Invalid composable token");return{rawToken:S,token:k,error:!1}}class C extends Error{email;constructor(e,t){super(e),this.name="UserNotFoundError",this.email=t}}class N extends Error{stsURL;constructor(e,t){super(e),this.name="STSError",this.stsURL=t}}const x="auth_state",O="auth_state_expiry";function D(){return{generateState:a(()=>{const e=crypto.randomUUID(),t=Date.now()+3e5;return sessionStorage.setItem(x,e),sessionStorage.setItem(O,t.toString()),e},[]),verifyState:a(e=>{if(!e)return"Missing state";const t=sessionStorage.getItem(x),o=parseInt(sessionStorage.getItem(O)||"0",10);let r;return r=t!==e?`State mismatched (${t} !== ${e})`:Date.now()>o?"State expired":void 0,r},[]),clearState:a(()=>{sessionStorage.removeItem(x),sessionStorage.removeItem(O)},[])}}function R(e){return!("firebase"===window.AUTH_MODE)}class q{isLoading=!0;client;authError;authToken;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(t,o){this.client=t||new m({serverUrl:e.endpoints.studio,storeUrl:e.endpoints.zeno,tokenServerUrl:e.endpoints.sts}),o&&(this.setSession=o),this.logout=this.logout.bind(this)}get store(){return this.client.store}get user(){return this.authToken}get account(){return this.authToken?.account}get project(){return this.authToken?.project}get accounts(){return this.authToken?.accounts}get authCallback(){return this.rawAuthToken.then(e=>`Bearer ${e}`)}get rawAuthToken(){return L().then(e=>{const o=e?.rawToken;if(!o)throw new Error("No token available");return this.authToken=t(o),o})}signOut(){this.logout()}getAccount(){return this.authToken?.account}async login(o,r={}){return this.authError=void 0,this.isLoading=!1,this.client.withAuthCallback(()=>this.authCallback),this.authToken=t(o),console.log(`Logging in as ${this.authToken?.name} with account ${this.authToken?.account.name} (${this.authToken?.account.id}, and project ${this.authToken?.project?.name} (${this.authToken?.project?.id})`),localStorage.setItem(w,this.authToken.account.id),localStorage.setItem(`${v}-${this.authToken.account.id}`,this.authToken.project?.id??""),e.onLogin?.(this.authToken),(r.loadOnboardingStatus??1)&&await this.fetchOnboardingStatus(),Promise.resolve()}isLoggedIn(){return!!this.authToken}logout(){if(console.log("Logging out"),R()){console.log("Using central auth logout"),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0);const e=new URL("https://internal-auth.vertesia.app/"),t=new URL(window.location.href);t.hash="",e.pathname="/logout",e.searchParams.set("redirect_uri",t.toString()),location.replace(e.toString())}else{console.log("Using Firebase logout");const e=!!this.authToken;this.authToken&&I().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0),e&&location.replace("/")}}async switchAccount(e){localStorage.setItem(w,e),this&&(this.account&&this.project?localStorage.setItem(`${v}-${this.account.id}`,this.project.id):this.account&&localStorage.removeItem(`${v}-${this.account.id}`)),window.location.replace(`/?a=${e}`)}async switchProject(e){this.account&&localStorage.setItem(`${v}-${this.account.id}`,e),window.location.replace(`/?a=${this.account?.id}&p=${e}`)}async fetchAccounts(){return this.client.accounts.list().then(e=>{if(!this.authToken)throw new Error("No token available");this.authToken.accounts=e,this.setSession?.(this.clone())}).catch(e=>{throw console.error("Failed to fetch accounts",e),e})}async fetchProjects(e){return this.client.projects.list([e]).then(t=>{if(!this.authToken)throw new Error("No token available");this.authToken={...this.authToken,accounts:this.authToken.accounts?.map(o=>o.id===e?{...o,projects:t.filter(t=>t.account===e)}:o)},this.setSession?.(this.clone())}).catch(e=>{throw console.error("Failed to fetch projects",e),e})}async fetchOnboardingStatus(){if(this.onboardingComplete)return console.log("Onboarding already completed"),!1;const e=this.onboardingComplete;try{const t=await this.client.account.onboardingProgress();if(this.onboardingComplete=Object.values(t).every(e=>!0===e),e!==this.onboardingComplete)return!0;this.setSession?.(this.clone())}catch(e){console.error("Error fetching onboarding status:",e),this.onboardingComplete=!1,this.setSession?.(this.clone())}return!1}clone(){const e=new q(this.client);return e.isLoading=this.isLoading,e.authError=this.authError,e.authToken=this.authToken,e.setSession=this.setSession,e.lastSelectedAccount=this.lastSelectedAccount,e.switchAccount=this.switchAccount,e.onboardingComplete=this.onboardingComplete,e}}const z=c(void 0);function H(){const e=l(z);if(!e)throw new Error("useUserSession must be used within a UserSessionProvider");return e}function B(){const{user:e}=H(),[t,o]=u(null),[r,n]=u(!0),[i,s]=u(null);return d(()=>{(async()=>{if(!e?.email)return o(null),void n(!1);try{const t=await fetch("/api/resolve-tenant",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tenantEmail:e.email})});if(t.ok){const e=await t.json();o(e?{tenantKey:e.name||"unknown",name:e.label||e.name||"Unknown",domain:e.domain||[],firebaseTenantId:e.firebaseTenantId,provider:e.provider,logo:e.logo}:null)}else o(null)}catch(e){console.error("Error loading current tenant:",e),s(g.getFixedT(null,f)("errors.failedToLoadTenantConfig")),o(null)}finally{n(!1)}})()},[e?.email]),{currentTenant:t,isLoading:r,error:i}}function G({children:t,loadOnboardingStatus:o=!0}){const r=new URLSearchParams(location.hash.substring(1)),n=r.get("token"),i=r.get("state"),[a,c]=u(new q),{generateState:l,verifyState:g,clearState:f}=D(),m=h(!1),S=h(void 0),k=(t,o)=>{const r=new URL(`https://internal-auth.vertesia.app/?sts=${e.endpoints.sts??"https://sts.vertesia.io"}`),n=new URL(window.location.href);n.hash="",r.searchParams.set("redirect_uri",n.toString()),r.searchParams.set("state",l()),location.replace(r.toString())};return S.current=()=>{if(m.current)return void console.log("Auth: skipping duplicate auth flow initiation");m.current=!0,console.log("Auth: starting auth flow"),e.logger.info("Starting auth flow");const t=new URL(window.location.href),r=t.searchParams.get("a")??localStorage.getItem(w)??void 0,l=t.searchParams.get("p")??localStorage.getItem(`${v}-${r}`)??void 0;if(console.log("Auth: selected account",r),console.log("Auth: selected project",l),e.logger.info("Selected account and project",{vertesia:{account_id:r,project_id:l}}),n&&i){a.setSession=c;const t=g(i);return t?(console.error(`Auth: invalid state: ${t}`),e.logger.error(`Invalid state: ${t}`,{vertesia:{state:i}}),k()):f(),void L(r,l,n,!1,R()).then(e=>{a.login(e.rawToken,{loadOnboardingStatus:o}).then(()=>{c(a.clone()),window.location.hash=""})}).catch(t=>t instanceof C?(console.log("User not found - will trigger signup flow",t),a.isLoading=!1,a.authError=t,void c(a.clone())):t instanceof N?(console.error("STS error during token exchange",t),e.logger.error("STS error during token exchange",{vertesia:{account_id:r,project_id:l,sts_url:t.stsURL,error:t}}),window.alert("Authentication failed due to an issue with the authentication service. Please try again later."),a.logout(),c(a.clone()),void(window.location.hash="")):(console.error("Failed to fetch user token from studio, redirecting to central auth",t),e.logger.error("Failed to fetch user token from studio, redirecting to central auth",{vertesia:{error:t}}),void k()))}if(!a.isLoggedIn()){if(console.log("Auth: not logged in & no token/state"),e.logger.info("Not logged in & no token/state",{vertesia:{account_id:r,project_id:l}}),R())return console.log("Auth: host is not in Firebase auth allowlist, redirecting to central auth with selection",r,l),e.logger.info("Redirecting to central auth with selection",{vertesia:{account_id:r,project_id:l}}),void k();console.log("Auth: host is in Firebase auth allowlist"),e.logger.info("Host is in Firebase auth allowlist",{vertesia:{account_id:r,project_id:l}})}return s(I(),async t=>{t?(console.log("Auth: successful login with firebase"),e.logger.info("Successful login with firebase",{vertesia:{account_id:r,project_id:l}}),a.setSession=c,await L(r,l,void 0,!1,R()).then(e=>{a.login(e.rawToken,{loadOnboardingStatus:o}).then(()=>c(a.clone()))}).catch(t=>{console.error("Failed to fetch user token from studio",t),e.logger.error("Failed to fetch user token from studio",{vertesia:{account_id:r,project_id:l,error:t}}),t instanceof C||a.logout(),a.isLoading=!1,a.authError=t,c(a.clone())})):(console.log("Auth: using anonymous user"),e.logger.info("Using anonymous user",{vertesia:{account_id:r,project_id:l}}),a.client.withAuthCallback(void 0),a.logout(),c(a.clone()))})},d(()=>S.current?.(),[]),p(z.Provider,{value:a,children:t})}function J(){return{tagUserSession:async e=>{const t=window.localStorage.getItem("composableSignupData");e?t&&window.localStorage.removeItem("composableSignupData"):console.error("No user found -- skipping tagging")},trackEvent:(t,o)=>{e.isProd||console.debug("track event",t,o),r(j(),t,{...o,debug_mode:!e.isProd})}}}export{w as LastSelectedAccountId_KEY,v as LastSelectedProjectId_KEY,N as STSError,C as UserNotFoundError,q as UserSession,z as UserSessionContext,G as UserSessionProvider,U as fetchComposableToken,A as fetchComposableTokenFromFirebaseToken,F as fetchComposableTokenFromVertesiaToken,L as getComposableToken,P as getCurrentVertesiaToken,j as getFirebaseAnalytics,y as getFirebaseApp,I as getFirebaseAuth,E as getFirebaseAuthToken,$ as setFirebaseTenant,D as useAuthState,B as useCurrentTenant,J as useUXTracking,H as useUserSession};
|
|
2
2
|
//# sourceMappingURL=vertesia-ui-session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertesia-ui-session.js","sources":["session/constants.js","session/auth/firebase.js","session/auth/composable.js","session/auth/useAuthState.js","session/auth/domainRouting.js","session/UserSession.js","session/auth/useCurrentTenant.js","session/UserSessionProvider.js","session/useUXTracking.js"],"sourcesContent":["export const LastSelectedAccountId_KEY = 'composableai.lastSelectedAccountId';\nexport const LastSelectedProjectId_KEY = 'composableai.lastSelectedProjectId';\n//# sourceMappingURL=constants.js.map","import { Env } from '@vertesia/ui/env';\nimport { getAnalytics } from 'firebase/analytics';\nimport { initializeApp } from 'firebase/app';\nimport { getAuth } from 'firebase/auth';\n// Use lazy initialization to avoid accessing Env before it's initialized\nlet _firebaseApp = null;\nlet _analytics = null;\nlet _firebaseAuth = null;\n// Getters that lazily initialize Firebase components when first accessed\nexport function getFirebaseApp() {\n if (!_firebaseApp) {\n try {\n if (!Env.firebase) {\n throw new Error('Firebase configuration is not available in the environment');\n }\n _firebaseApp = initializeApp(Env.firebase);\n }\n catch (error) {\n console.error('Failed to initialize Firebase app:', error);\n throw new Error('Firebase initialization failed - environment may not be properly initialized', {\n cause: error,\n });\n }\n }\n return _firebaseApp;\n}\nexport function getFirebaseAnalytics() {\n if (!_analytics) {\n _analytics = getAnalytics(getFirebaseApp());\n }\n return _analytics;\n}\nexport function getFirebaseAuth() {\n if (!_firebaseAuth) {\n _firebaseAuth = getAuth(getFirebaseApp());\n }\n return _firebaseAuth;\n}\nexport async function setFirebaseTenant(tenantEmail) {\n if (!tenantEmail) {\n console.log('No tenant name or email specified, skipping tenant setup');\n return;\n }\n if (!Env.firebase) {\n console.log('Firebase configuration is not available in the environment');\n return;\n }\n try {\n if (tenantEmail)\n console.log(`Resolving tenant ID from email: ${tenantEmail}`);\n // Add retry logic with exponential backoff\n let retries = 3;\n let retryDelay = 250; // Start with 250ms delay\n while (retries > 0) {\n try {\n // Call the API endpoint to resolve the tenant ID\n const response = await fetch('/api/resolve-tenant', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n tenantEmail: tenantEmail,\n }),\n // Add timeout to prevent hanging requests\n signal: AbortSignal.timeout(5000),\n });\n // Check for network errors\n if (!response) {\n throw new Error('No response received from tenant API');\n }\n // Handle HTTP error responses\n if (!response.ok) {\n // Try to parse the error response\n try {\n const errorData = await response.json();\n console.error('Failed to resolve tenant ID:', errorData.error);\n }\n catch {\n console.error(`Failed to resolve tenant ID: HTTP ${response.status}`);\n }\n // If the error is 404 Not Found, no need to retry\n if (response.status === 404) {\n console.warn(`Tenant not found for ${tenantEmail}`);\n return;\n }\n throw new Error(`HTTP error ${response.status}`);\n }\n // Successfully got a response, parse it\n const data = (await response.json());\n if (data?.firebaseTenantId) {\n const auth = getFirebaseAuth();\n auth.tenantId = data.firebaseTenantId;\n Env.firebase.providerType = data.provider ?? 'oidc';\n console.log(`Tenant ID set to ${auth.tenantId}`);\n return data;\n }\n else {\n console.error(`Invalid response format, missing tenantId for ${tenantEmail}`);\n return; // No need to retry for invalid response format\n }\n }\n catch (fetchError) {\n // Only retry for network-related errors\n if (retries > 1) {\n console.warn(`Tenant resolution failed, retrying in ${retryDelay}ms...`, fetchError);\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n retryDelay *= 2; // Exponential backoff\n retries--;\n }\n else {\n throw fetchError; // Last retry failed, propagate error\n }\n }\n }\n }\n catch (error) {\n // Final error handler\n console.error('Error setting Firebase tenant:', error instanceof Error ? error.message : 'Unknown error');\n // Continue without tenant ID - authentication will work without multi-tenancy\n // but the user will access the default tenant\n }\n}\nexport async function getFirebaseAuthToken(refresh) {\n const auth = getFirebaseAuth();\n const user = auth.currentUser;\n if (user) {\n return user\n .getIdToken(refresh)\n .then((token) => {\n Env.logger.info('Got Firebase token', {\n vertesia: {\n user_email: user.email,\n user_name: user.displayName,\n user_id: user.uid,\n refresh: refresh,\n },\n });\n return token;\n })\n .catch((err) => {\n Env.logger.error('Failed to get Firebase token', {\n vertesia: {\n user_email: user.email,\n user_name: user.displayName,\n user_id: user.uid,\n refresh: refresh,\n error: err,\n },\n });\n console.error('Failed to get access token', err);\n return null;\n });\n }\n else {\n Env.logger.warn('No user found');\n return Promise.resolve(null);\n }\n}\n//# sourceMappingURL=firebase.js.map","import { Env } from '@vertesia/ui/env';\nimport { jwtDecode } from 'jwt-decode';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from '../constants';\nimport { getFirebaseAuth, getFirebaseAuthToken } from './firebase';\nlet AUTH_TOKEN_RAW;\nlet AUTH_TOKEN;\nfunction normalizeIssuer(value) {\n return value?.replace(/\\/+$/, '');\n}\nfunction decodeToken(token) {\n return jwtDecode(token);\n}\nfunction isVertesiaIssuedToken(token) {\n if (!token)\n return false;\n try {\n const decoded = decodeToken(token);\n return normalizeIssuer(decoded.iss) === normalizeIssuer(Env.endpoints.sts);\n }\n catch {\n return false;\n }\n}\nexport async function fetchComposableToken(getIdToken, accountId, projectId, ttl, retryCount = 0) {\n console.log(`Getting/refreshing composable token for account ${accountId} and project ${projectId} `);\n Env.logger.info('Getting/refreshing composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n retry_count: retryCount,\n },\n });\n const idToken = await getIdToken(); //get from firebase\n if (!idToken) {\n console.log('No id token found - using cookie auth');\n throw new Error('No id token found');\n }\n // Use STS endpoint - either configured or default to sts.vertesia.io\n const stsEndpoint = Env.endpoints.sts;\n console.log('Using STS for token generation:', stsEndpoint);\n Env.logger.info('Using STS for token generation', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n sts_url: stsEndpoint,\n },\n });\n try {\n // Call STS to generate a user token\n const stsUrl = new URL(`${stsEndpoint}/token/issue`);\n const requestBody = {\n type: 'user',\n account_id: accountId,\n project_id: projectId,\n expires_at: ttl ? Math.floor(Date.now() / 1000) + ttl : undefined,\n };\n const stsRes = await fetch(stsUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${idToken}`, // Firebase token for authentication\n },\n body: JSON.stringify(requestBody),\n }).catch((error) => {\n console.error('Failed to call STS endpoint', error);\n Env.logger.error('Failed to call STS endpoint', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: error,\n },\n });\n throw new STSError('Failed to call STS endpoint', stsEndpoint);\n });\n if (idToken && stsRes?.status === 404) {\n // User not found in token-server - call ensure-user endpoint\n console.log('404: User not found - calling ensure-user endpoint');\n Env.logger.info('404: User not found - calling ensure-user endpoint', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes?.status,\n },\n });\n const ensureResponse = await fetch(`${Env.endpoints.studio}/auth/ensure-user`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${idToken}`,\n 'Content-Type': 'application/json',\n },\n });\n if (ensureResponse.status === 412) {\n // No invite - trigger signup\n console.log('412: No invite found - signup required');\n Env.logger.info('412: No invite found - signup required', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n const idTokenDecoded = jwtDecode(idToken);\n if (!idTokenDecoded?.email) {\n Env.logger.error('No email found in id token');\n throw new Error('No email found in id token');\n }\n throw new UserNotFoundError('User not found - signup required', idTokenDecoded.email);\n }\n if (ensureResponse.status === 403) {\n // SigninScreen keys the invite-required view off this message.\n Env.logger.warn('403: Customer-domain user requires an invite to join', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n throw new Error('Customer-domain user requires an invite to join');\n }\n if (!ensureResponse.ok) {\n console.error('Failed to ensure user exists', ensureResponse.status);\n Env.logger.error('Failed to ensure user exists', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: ensureResponse.status,\n },\n });\n throw new Error('Failed to ensure user exists');\n }\n // User created/exists - retry token generation\n console.log('User ensured - retrying token generation');\n Env.logger.info('User ensured - retrying token generation', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n return fetchComposableToken(getIdToken, accountId, projectId, ttl, retryCount);\n }\n if (idToken && stsRes?.status === 412) {\n console.log(\"412: auth succeeded but user doesn't exist - signup required\", stsRes?.status);\n Env.logger.error(\"412: auth succeeded but user doesn't exist - signup required\", {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes?.status,\n },\n });\n const idTokenDecoded = jwtDecode(idToken);\n if (!idTokenDecoded?.email) {\n Env.logger.error('No email found in id token');\n throw new Error('No email found in id token');\n }\n Env.logger.error('User not found', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n email: idTokenDecoded.email,\n },\n });\n throw new UserNotFoundError('User not found', idTokenDecoded.email);\n }\n if (stsRes.status === 403) {\n // User doesn't have access to the requested account/project, or has no accounts\n // This can happen with:\n // 1. Stale localStorage from previous user\n // 2. User invited to a new account (doesn't have access yet)\n // 3. User exists but has no accounts at all\n if (retryCount > 0) {\n // Already retried without account scope - this is a real authorization failure\n console.error('403: Access denied even without account scope - user may have no accounts');\n Env.logger.error('403: Access denied after retry - authorization failure', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes.status,\n retry_count: retryCount,\n },\n });\n throw new Error('Access denied - user may not have access to any accounts');\n }\n console.log('403: Access denied - clearing cached account and retrying without account scope');\n Env.logger.warn('403: Access denied - clearing cached account and retrying', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes.status,\n retry_count: retryCount,\n },\n });\n // Clear any stale account/project from localStorage\n localStorage.removeItem(LastSelectedAccountId_KEY);\n if (accountId) {\n localStorage.removeItem(`${LastSelectedProjectId_KEY}-${accountId}`);\n }\n // Retry without account/project scope - let user log in to their default account\n return fetchComposableToken(getIdToken, undefined, undefined, ttl, retryCount + 1);\n }\n if (!stsRes.ok) {\n const errorText = await stsRes.text();\n console.error('STS token generation failed:', stsRes.status, errorText);\n Env.logger.error('STS token generation failed', {\n vertesia: {\n status: stsRes.status,\n error: errorText,\n account_id: accountId,\n project_id: projectId,\n },\n });\n throw new Error(`Failed to get token from STS: ${stsRes.status}`);\n }\n const { token } = await stsRes.json();\n console.log('Successfully got token from STS');\n Env.logger.info('Successfully got token from STS');\n return token;\n }\n catch (error) {\n if (error instanceof UserNotFoundError || error instanceof STSError) {\n throw error; // Re-throw UserNotFoundError and STSError to be handled separately in the caller\n }\n // Clear any stale account/project from localStorage on error\n localStorage.removeItem(LastSelectedAccountId_KEY);\n if (accountId) {\n localStorage.removeItem(`${LastSelectedProjectId_KEY}-${accountId}`);\n }\n console.error('Failed to get composable token from STS', error);\n Env.logger.error('Failed to get composable token from STS', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: error,\n },\n });\n throw new Error('Failed to get composable token', { cause: error });\n }\n}\n/**\n *\n * @param accountId\n * @param projectId\n * @param ttl time to live for the token in seconds\n * @returns\n */\nexport async function fetchComposableTokenFromFirebaseToken(accountId, projectId, ttl) {\n return fetchComposableToken(getFirebaseAuthToken, accountId, projectId, ttl);\n}\n/**\n * Mint a scoped Vertesia token from an existing Vertesia JWT. STS accepts STS-issued\n * tokens on /token/issue, so this works for sessions established via Central Auth where\n * the browser has no Firebase user.\n */\nexport async function fetchComposableTokenFromVertesiaToken(vertesiaToken, accountId, projectId, ttl) {\n return fetchComposableToken(() => Promise.resolve(vertesiaToken), accountId, projectId, ttl);\n}\n/** Returns the cached Vertesia raw JWT, if any. Does not refresh. */\nexport function getCurrentVertesiaToken() {\n return AUTH_TOKEN_RAW;\n}\nexport async function getComposableToken(accountId, projectId, initToken, forceRefresh = false, useInternalAuth = false) {\n const selectedAccount = accountId ?? localStorage.getItem(LastSelectedAccountId_KEY) ?? undefined;\n const selectedProject = projectId ?? localStorage.getItem(`${LastSelectedProjectId_KEY}-${selectedAccount}`) ?? undefined;\n const devAuthToken = Env.isLocalDev ? Env.devAuthToken : undefined;\n const suppliedToken = devAuthToken ?? initToken ?? AUTH_TOKEN_RAW;\n //token is still valid for more than 5 minutes\n if (!forceRefresh && AUTH_TOKEN_RAW && AUTH_TOKEN && AUTH_TOKEN.exp > Date.now() / 1000 + 300) {\n return { rawToken: AUTH_TOKEN_RAW, token: AUTH_TOKEN, error: false };\n }\n if (!forceRefresh && isVertesiaIssuedToken(suppliedToken)) {\n AUTH_TOKEN_RAW = suppliedToken;\n AUTH_TOKEN = decodeToken(AUTH_TOKEN_RAW);\n if (!AUTH_TOKEN.exp) {\n throw new Error('Invalid composable token');\n }\n return { rawToken: AUTH_TOKEN_RAW, token: AUTH_TOKEN, error: false };\n }\n //token is close to expire, refresh it\n if (!devAuthToken && !useInternalAuth && getFirebaseAuth().currentUser) {\n //we have a firebase user, get the token from there\n AUTH_TOKEN_RAW = await fetchComposableTokenFromFirebaseToken(selectedAccount, selectedProject);\n }\n else if (!devAuthToken && (initToken || AUTH_TOKEN_RAW)) {\n // we have a token already and no firebase user, refresh it\n AUTH_TOKEN_RAW = await fetchComposableToken(() => Promise.resolve(initToken ?? AUTH_TOKEN_RAW), selectedAccount, selectedProject);\n }\n else if (devAuthToken) {\n AUTH_TOKEN_RAW = devAuthToken;\n }\n if (!AUTH_TOKEN_RAW) {\n Env.logger.error('Cannot acquire a composable token', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n throw new Error('Cannot acquire a composable token');\n }\n AUTH_TOKEN = decodeToken(AUTH_TOKEN_RAW);\n if (!AUTH_TOKEN?.exp || !AUTH_TOKEN_RAW) {\n console.error('Invalid composable token', AUTH_TOKEN);\n Env.logger.error('Invalid composable token', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n throw new Error('Invalid composable token');\n }\n return { rawToken: AUTH_TOKEN_RAW, token: AUTH_TOKEN, error: false };\n}\nexport class UserNotFoundError extends Error {\n email;\n constructor(message, email) {\n super(message);\n this.name = 'UserNotFoundError';\n this.email = email;\n }\n}\nexport class STSError extends Error {\n stsURL;\n constructor(message, stsURL) {\n super(message);\n this.name = 'STSError';\n this.stsURL = stsURL;\n }\n}\n//# sourceMappingURL=composable.js.map","/**\n * This hook is used to generate and verify state for OAuth2 authorization requests.\n * @returns\n */\nimport { useCallback } from 'react';\nconst AUTH_STATE_KEY = 'auth_state';\nconst STATE_EXPIRY_KEY = 'auth_state_expiry';\nconst STATE_TTL = 5 * 60 * 1000; // 5 min\nexport function useAuthState() {\n // Generate new state\n const generateState = useCallback(() => {\n const state = crypto.randomUUID();\n const expiryTime = Date.now() + STATE_TTL;\n // Store state and expiry\n sessionStorage.setItem(AUTH_STATE_KEY, state);\n sessionStorage.setItem(STATE_EXPIRY_KEY, expiryTime.toString());\n return state;\n }, []);\n // Verify returned state\n const verifyState = useCallback((returnedState) => {\n if (!returnedState) {\n return 'Missing state';\n }\n const savedState = sessionStorage.getItem(AUTH_STATE_KEY);\n const expiryTime = parseInt(sessionStorage.getItem(STATE_EXPIRY_KEY) || '0', 10);\n let reason;\n // Verify state matches and hasn't expired\n if (savedState !== returnedState) {\n reason = `State mismatched (${savedState} !== ${returnedState})`;\n }\n else if (Date.now() > expiryTime) {\n reason = 'State expired';\n }\n else {\n reason = undefined; // No errors\n }\n return reason;\n }, []);\n // Clear state (useful for cleanup)\n const clearState = useCallback(() => {\n sessionStorage.removeItem(AUTH_STATE_KEY);\n sessionStorage.removeItem(STATE_EXPIRY_KEY);\n }, []);\n return { generateState, verifyState, clearState };\n}\n//# sourceMappingURL=useAuthState.js.map","export function shouldUseFirebaseAuth(_hostname) {\n return window.AUTH_MODE === 'firebase';\n}\nexport function shouldRedirectToCentralAuth(_hostname) {\n return !shouldUseFirebaseAuth();\n}\n//# sourceMappingURL=domainRouting.js.map","import { VertesiaClient } from '@vertesia/client';\nimport { Env } from '@vertesia/ui/env';\nimport { jwtDecode } from 'jwt-decode';\nimport { createContext, useContext } from 'react';\nimport { getComposableToken } from './auth/composable';\nimport { shouldRedirectToCentralAuth } from './auth/domainRouting';\nimport { getFirebaseAuth } from './auth/firebase';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from './constants';\nexport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY };\nconst CENTRAL_AUTH_REDIRECT = 'https://internal-auth.vertesia.app/';\nclass UserSession {\n isLoading = true;\n client;\n authError;\n authToken;\n setSession;\n lastSelectedAccount;\n lastSelectedProject;\n onboardingComplete;\n constructor(client, setSession) {\n if (client) {\n this.client = client;\n }\n else {\n this.client = new VertesiaClient({\n serverUrl: Env.endpoints.studio,\n storeUrl: Env.endpoints.zeno,\n tokenServerUrl: Env.endpoints.sts,\n });\n }\n if (setSession) {\n this.setSession = setSession;\n }\n this.logout = this.logout.bind(this);\n }\n get store() {\n return this.client.store;\n }\n get user() {\n //compatibility\n return this.authToken;\n }\n get account() {\n //compatibility\n return this.authToken?.account;\n }\n get project() {\n return this.authToken?.project;\n }\n get accounts() {\n //compatibility\n return this.authToken?.accounts;\n }\n get authCallback() {\n return this.rawAuthToken.then((token) => `Bearer ${token}`);\n }\n get rawAuthToken() {\n return getComposableToken().then((res) => {\n const token = res?.rawToken;\n if (!token) {\n throw new Error('No token available');\n }\n this.authToken = jwtDecode(token);\n return token;\n });\n }\n /**\n * Force a fresh Vertesia JWT from STS, bypassing the in-memory cache.\n * Use this when the current token's claims (e.g. `apps`) are suspected\n * stale — STS recomputes the `apps` claim from ACEs on every issuance.\n */\n async refreshAuthToken() {\n const res = await getComposableToken(undefined, undefined, undefined, true);\n const token = res?.rawToken;\n if (!token) {\n throw new Error('No token available');\n }\n this.authToken = jwtDecode(token);\n this.setSession?.(this.clone());\n return this.authToken;\n }\n signOut() {\n //compatibility\n this.logout();\n }\n getAccount() {\n return this.authToken?.account;\n }\n async login(token, options = {}) {\n this.authError = undefined;\n this.isLoading = false;\n this.client.withAuthCallback(() => this.authCallback);\n this.authToken = jwtDecode(token);\n console.log(`Logging in as ${this.authToken?.name} with account ${this.authToken?.account.name} (${this.authToken?.account.id}, and project ${this.authToken?.project?.name} (${this.authToken?.project?.id})`);\n //store selected account in local storage\n localStorage.setItem(LastSelectedAccountId_KEY, this.authToken.account.id);\n localStorage.setItem(`${LastSelectedProjectId_KEY}-${this.authToken.account.id}`, this.authToken.project?.id ?? '');\n // notify the host app of the login\n Env.onLogin?.(this.authToken);\n if (options.loadOnboardingStatus ?? true) {\n await this.fetchOnboardingStatus();\n }\n return Promise.resolve();\n }\n isLoggedIn() {\n return !!this.authToken;\n }\n logout() {\n console.log('Logging out');\n if (shouldRedirectToCentralAuth()) {\n // Redirect to central auth for logout\n // Central auth will handle Firebase logout\n console.log('Using central auth logout');\n this.authError = undefined;\n this.isLoading = false;\n this.authToken = undefined;\n this.setSession = undefined;\n this.client.withAuthCallback(undefined);\n const logoutUrl = new URL(CENTRAL_AUTH_REDIRECT);\n const currentUrl = new URL(window.location.href);\n currentUrl.hash = '';\n logoutUrl.pathname = '/logout';\n logoutUrl.searchParams.set('redirect_uri', currentUrl.toString());\n location.replace(logoutUrl.toString());\n }\n else {\n // Use Firebase logout directly\n console.log('Using Firebase logout');\n const wasLoggedIn = !!this.authToken;\n if (this.authToken) {\n void getFirebaseAuth().signOut();\n }\n this.authError = undefined;\n this.isLoading = false;\n this.authToken = undefined;\n this.setSession = undefined;\n this.client.withAuthCallback(undefined);\n // Navigate to root to avoid React rendering errors when\n // unmounting deeply nested route components during logout.\n // Only navigate if user was actually logged in to avoid\n // infinite reload loop on fresh/incognito sessions.\n if (wasLoggedIn) {\n location.replace('/');\n }\n }\n }\n async switchAccount(targetAccountId) {\n localStorage.setItem(LastSelectedAccountId_KEY, targetAccountId);\n if (this) {\n if (this.account && this.project) {\n localStorage.setItem(`${LastSelectedProjectId_KEY}-${this.account.id}`, this.project.id);\n }\n else if (this.account) {\n localStorage.removeItem(`${LastSelectedProjectId_KEY}-${this.account.id}`);\n }\n }\n window.location.replace(`/?a=${targetAccountId}`);\n }\n async switchProject(targetProjectId) {\n if (this.account) {\n localStorage.setItem(`${LastSelectedProjectId_KEY}-${this.account.id}`, targetProjectId);\n }\n window.location.replace(`/?a=${this.account?.id}&p=${targetProjectId}`);\n }\n async fetchAccounts() {\n return this.client.accounts\n .list()\n .then((accounts) => {\n if (!this.authToken) {\n throw new Error('No token available');\n }\n this.authToken.accounts = accounts;\n this.setSession?.(this.clone());\n })\n .catch((err) => {\n console.error('Failed to fetch accounts', err);\n throw err;\n });\n }\n async fetchProjects(accountId) {\n return this.client.projects\n .list([accountId])\n .then((projects) => {\n if (!this.authToken) {\n throw new Error('No token available');\n }\n this.authToken = {\n ...this.authToken,\n accounts: this.authToken.accounts?.map((account) => {\n if (account.id === accountId) {\n return {\n ...account,\n projects: projects.filter((project) => project.account === accountId),\n };\n }\n return account;\n }),\n };\n this.setSession?.(this.clone());\n })\n .catch((err) => {\n console.error('Failed to fetch projects', err);\n throw err;\n });\n }\n async fetchOnboardingStatus() {\n if (this.onboardingComplete) {\n console.log('Onboarding already completed');\n return false;\n }\n const previousStatus = this.onboardingComplete;\n try {\n const onboarding = await this.client.account.onboardingProgress();\n this.onboardingComplete = Object.values(onboarding).every((value) => value === true);\n if (previousStatus !== this.onboardingComplete) {\n return true;\n }\n this.setSession?.(this.clone());\n }\n catch (error) {\n console.error('Error fetching onboarding status:', error);\n this.onboardingComplete = false;\n this.setSession?.(this.clone());\n }\n return false;\n }\n clone() {\n const session = new UserSession(this.client);\n session.isLoading = this.isLoading;\n session.authError = this.authError;\n session.authToken = this.authToken;\n session.setSession = this.setSession;\n session.lastSelectedAccount = this.lastSelectedAccount;\n session.switchAccount = this.switchAccount;\n session.onboardingComplete = this.onboardingComplete;\n return session;\n }\n}\nconst UserSessionContext = createContext(undefined);\nexport function useUserSession() {\n const session = useContext(UserSessionContext);\n if (!session) {\n throw new Error('useUserSession must be used within a UserSessionProvider');\n }\n return session;\n}\nexport { UserSession, UserSessionContext };\n//# sourceMappingURL=UserSession.js.map","import { i18nInstance, NAMESPACE } from '@vertesia/ui/i18n';\nimport { useEffect, useState } from 'react';\nimport { useUserSession } from '../UserSession';\nexport function useCurrentTenant() {\n const { user } = useUserSession();\n const [currentTenant, setCurrentTenant] = useState(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState(null);\n useEffect(() => {\n const loadCurrentTenant = async () => {\n if (!user?.email) {\n setCurrentTenant(null);\n setIsLoading(false);\n return;\n }\n try {\n const response = await fetch('/api/resolve-tenant', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n tenantEmail: user.email,\n }),\n });\n if (response.ok) {\n const tenantData = await response.json();\n if (tenantData) {\n // Convert the resolved tenant data to our TenantConfig format\n setCurrentTenant({\n tenantKey: tenantData.name || 'unknown',\n name: tenantData.label || tenantData.name || 'Unknown',\n domain: tenantData.domain || [],\n firebaseTenantId: tenantData.firebaseTenantId,\n provider: tenantData.provider,\n logo: tenantData.logo,\n });\n }\n else {\n setCurrentTenant(null);\n }\n }\n else {\n setCurrentTenant(null);\n }\n }\n catch (error) {\n console.error('Error loading current tenant:', error);\n setError(i18nInstance.getFixedT(null, NAMESPACE)('errors.failedToLoadTenantConfig'));\n setCurrentTenant(null);\n }\n finally {\n setIsLoading(false);\n }\n };\n void loadCurrentTenant();\n }, [user?.email]);\n return {\n currentTenant,\n isLoading,\n error,\n };\n}\n//# sourceMappingURL=useCurrentTenant.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { Env } from '@vertesia/ui/env';\nimport { onAuthStateChanged } from 'firebase/auth';\nimport { useEffect, useRef, useState } from 'react';\nimport { getComposableToken, STSError, UserNotFoundError } from './auth/composable';\nimport { shouldRedirectToCentralAuth } from './auth/domainRouting';\nimport { getFirebaseAuth } from './auth/firebase';\nimport { useAuthState } from './auth/useAuthState';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY, UserSession, UserSessionContext } from './UserSession';\nconst CENTRAL_AUTH_REDIRECT = 'https://internal-auth.vertesia.app/';\nexport function UserSessionProvider({ children, loadOnboardingStatus = true }) {\n const hashParams = new URLSearchParams(location.hash.substring(1));\n const token = hashParams.get('token');\n const state = hashParams.get('state');\n const [session, setSession] = useState(new UserSession());\n const { generateState, verifyState, clearState } = useAuthState();\n const hasInitiatedAuthRef = useRef(false);\n const authFlowRef = useRef(undefined);\n const redirectToCentralAuth = (projectId, accountId) => {\n const url = new URL(`${CENTRAL_AUTH_REDIRECT}?sts=${Env.endpoints.sts ?? 'https://sts.vertesia.io'}`);\n const currentUrl = new URL(window.location.href);\n currentUrl.hash = '';\n if (projectId)\n currentUrl.searchParams.set('p', projectId);\n if (accountId)\n currentUrl.searchParams.set('a', accountId);\n url.searchParams.set('redirect_uri', currentUrl.toString());\n url.searchParams.set('state', generateState());\n location.replace(url.toString());\n };\n authFlowRef.current = () => {\n // Make this effect idempotent - only run auth flow once\n if (hasInitiatedAuthRef.current) {\n console.log('Auth: skipping duplicate auth flow initiation');\n return;\n }\n hasInitiatedAuthRef.current = true;\n console.log('Auth: starting auth flow');\n Env.logger.info('Starting auth flow');\n const currentUrl = new URL(window.location.href);\n const selectedAccount = currentUrl.searchParams.get('a') ?? localStorage.getItem(LastSelectedAccountId_KEY) ?? undefined;\n const selectedProject = currentUrl.searchParams.get('p') ??\n localStorage.getItem(`${LastSelectedProjectId_KEY}-${selectedAccount}`) ??\n undefined;\n console.log('Auth: selected account', selectedAccount);\n console.log('Auth: selected project', selectedProject);\n Env.logger.info('Selected account and project', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n if (Env.isLocalDev && Env.devAuthToken) {\n session.setSession = setSession;\n getComposableToken(selectedAccount, selectedProject, Env.devAuthToken)\n .then((res) => {\n session.login(res.rawToken).then(() => setSession(session.clone()));\n })\n .catch((err) => {\n console.error('Failed to initialize dev auth token', err);\n Env.logger.error('Failed to initialize dev auth token', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n error: err,\n },\n });\n session.isLoading = false;\n session.authError = err instanceof Error ? err : new Error(String(err));\n setSession(session.clone());\n });\n return;\n }\n if (token && state) {\n session.setSession = setSession;\n const validationError = verifyState(state);\n if (validationError) {\n console.error(`Auth: invalid state: ${validationError}`);\n Env.logger.error(`Invalid state: ${validationError}`, {\n vertesia: {\n state: state,\n },\n });\n redirectToCentralAuth();\n }\n else {\n clearState();\n }\n getComposableToken(selectedAccount, selectedProject, token, false, shouldRedirectToCentralAuth())\n .then((res) => {\n session.login(res.rawToken, { loadOnboardingStatus }).then(() => {\n setSession(session.clone());\n //cleanup the hash\n window.location.hash = '';\n });\n })\n .catch((err) => {\n // Don't redirect to central auth for UserNotFoundError - let signup flow handle it\n if (err instanceof UserNotFoundError) {\n console.log('User not found - will trigger signup flow', err);\n session.isLoading = false;\n session.authError = err;\n setSession(session.clone());\n return;\n }\n if (err instanceof STSError) {\n console.error('STS error during token exchange', err);\n Env.logger.error('STS error during token exchange', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n sts_url: err.stsURL,\n error: err,\n },\n });\n window.alert('Authentication failed due to an issue with the authentication service. Please try again later.');\n session.logout();\n setSession(session.clone());\n window.location.hash = '';\n return;\n }\n console.error('Failed to fetch user token from studio, redirecting to central auth', err);\n Env.logger.error('Failed to fetch user token from studio, redirecting to central auth', {\n vertesia: {\n error: err,\n },\n });\n redirectToCentralAuth();\n });\n return;\n }\n let cancelled = false;\n let unsubscribe;\n const startFirebaseOrCentralAuth = () => {\n if (cancelled)\n return;\n // If the current host is not in the Firebase allowlist, central auth owns sign-in.\n if (!session.isLoggedIn()) {\n console.log('Auth: not logged in & no token/state');\n Env.logger.info('Not logged in & no token/state', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n if (shouldRedirectToCentralAuth()) {\n console.log('Auth: host is not in Firebase auth allowlist, redirecting to central auth with selection', selectedAccount, selectedProject);\n Env.logger.info('Redirecting to central auth with selection', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n redirectToCentralAuth();\n return; // Don't register onAuthStateChanged listener when redirecting\n }\n console.log('Auth: host is in Firebase auth allowlist');\n Env.logger.info('Host is in Firebase auth allowlist', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n }\n unsubscribe = onAuthStateChanged(getFirebaseAuth(), async (firebaseUser) => {\n if (firebaseUser) {\n console.log('Auth: successful login with firebase');\n Env.logger.info('Successful login with firebase', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n session.setSession = setSession;\n await getComposableToken(selectedAccount, selectedProject, undefined, false, shouldRedirectToCentralAuth())\n .then((res) => {\n session\n .login(res.rawToken, { loadOnboardingStatus })\n .then(() => setSession(session.clone()));\n })\n .catch((err) => {\n console.error('Failed to fetch user token from studio', err);\n Env.logger.error('Failed to fetch user token from studio', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n error: err,\n },\n });\n if (!(err instanceof UserNotFoundError))\n session.logout();\n session.isLoading = false;\n session.authError = err;\n setSession(session.clone());\n });\n }\n else {\n // anonymous user\n console.log('Auth: using anonymous user');\n Env.logger.info('Using anonymous user', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n session.client.withAuthCallback(undefined);\n session.logout();\n setSession(session.clone());\n }\n });\n };\n if (Env.authTokenProvider) {\n session.setSession = setSession;\n void Env.authTokenProvider()\n .then(async (injectedToken) => {\n if (!injectedToken) {\n startFirebaseOrCentralAuth();\n return;\n }\n const res = await getComposableToken(selectedAccount, selectedProject, injectedToken, false, shouldRedirectToCentralAuth());\n await session.login(res.rawToken, { loadOnboardingStatus });\n if (!cancelled)\n setSession(session.clone());\n })\n .catch((err) => {\n console.warn('Auth: failed to initialize injected auth token', err);\n Env.logger.warn('Failed to initialize injected auth token', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n error: err,\n },\n });\n startFirebaseOrCentralAuth();\n });\n return () => {\n cancelled = true;\n unsubscribe?.();\n };\n }\n startFirebaseOrCentralAuth();\n return () => {\n cancelled = true;\n unsubscribe?.();\n };\n };\n useEffect(() => {\n return authFlowRef.current?.();\n }, []);\n return _jsx(UserSessionContext.Provider, { value: session, children: children });\n}\n//# sourceMappingURL=UserSessionProvider.js.map","import { Env } from '@vertesia/ui/env';\nimport { logEvent } from 'firebase/analytics';\nimport { getFirebaseAnalytics } from './auth/firebase';\nexport function useUXTracking() {\n //identify user in monitoring and UX systems\n const tagUserSession = async (user) => {\n const signupData = window.localStorage.getItem('composableSignupData');\n if (!user) {\n console.error('No user found -- skipping tagging');\n return;\n }\n if (signupData) {\n window.localStorage.removeItem('composableSignupData');\n }\n };\n //send event to analytics and UX systems\n const trackEvent = (eventName, eventProperties) => {\n if (!Env.isProd) {\n console.debug('track event', eventName, eventProperties);\n }\n //GA via firebase\n logEvent(getFirebaseAnalytics(), eventName, { ...eventProperties, debug_mode: !Env.isProd });\n };\n return {\n tagUserSession,\n trackEvent,\n };\n}\n//# sourceMappingURL=useUXTracking.js.map"],"names":["LastSelectedAccountId_KEY","LastSelectedProjectId_KEY","AUTH_TOKEN_RAW","AUTH_TOKEN","_firebaseApp","_analytics","_firebaseAuth","getFirebaseApp","Env","firebase","Error","initializeApp","error","console","cause","getFirebaseAnalytics","getAnalytics","getFirebaseAuth","getAuth","async","setFirebaseTenant","tenantEmail","log","retries","retryDelay","response","fetch","method","headers","body","JSON","stringify","signal","AbortSignal","timeout","ok","errorData","json","status","warn","data","firebaseTenantId","auth","tenantId","providerType","provider","fetchError","Promise","resolve","setTimeout","message","getFirebaseAuthToken","refresh","user","currentUser","getIdToken","then","token","logger","info","vertesia","user_email","email","user_name","displayName","user_id","uid","catch","err","normalizeIssuer","value","replace","decodeToken","jwtDecode","fetchComposableToken","accountId","projectId","ttl","retryCount","account_id","project_id","retry_count","idToken","stsEndpoint","endpoints","sts","sts_url","stsUrl","URL","requestBody","type","expires_at","Math","floor","Date","now","undefined","stsRes","Authorization","STSError","ensureResponse","studio","idTokenDecoded","UserNotFoundError","localStorage","removeItem","errorText","text","fetchComposableTokenFromFirebaseToken","fetchComposableTokenFromVertesiaToken","vertesiaToken","getCurrentVertesiaToken","getComposableToken","initToken","forceRefresh","useInternalAuth","selectedAccount","getItem","selectedProject","devAuthToken","isLocalDev","suppliedToken","exp","rawToken","iss","isVertesiaIssuedToken","constructor","super","this","name","stsURL","AUTH_STATE_KEY","STATE_EXPIRY_KEY","useAuthState","generateState","useCallback","state","crypto","randomUUID","expiryTime","sessionStorage","setItem","toString","verifyState","returnedState","savedState","parseInt","reason","clearState","shouldRedirectToCentralAuth","_hostname","window","AUTH_MODE","UserSession","isLoading","client","authError","authToken","setSession","lastSelectedAccount","lastSelectedProject","onboardingComplete","VertesiaClient","serverUrl","storeUrl","zeno","tokenServerUrl","logout","bind","store","account","project","accounts","authCallback","rawAuthToken","res","refreshAuthToken","clone","signOut","getAccount","login","options","withAuthCallback","id","onLogin","loadOnboardingStatus","fetchOnboardingStatus","isLoggedIn","logoutUrl","currentUrl","location","href","hash","pathname","searchParams","set","wasLoggedIn","switchAccount","targetAccountId","switchProject","targetProjectId","fetchAccounts","list","fetchProjects","projects","map","filter","previousStatus","onboarding","onboardingProgress","Object","values","every","session","UserSessionContext","createContext","useUserSession","useContext","useCurrentTenant","currentTenant","setCurrentTenant","useState","setIsLoading","setError","useEffect","tenantData","tenantKey","label","domain","logo","i18nInstance","getFixedT","NAMESPACE","loadCurrentTenant","UserSessionProvider","children","hashParams","URLSearchParams","substring","get","hasInitiatedAuthRef","useRef","authFlowRef","redirectToCentralAuth","url","current","String","validationError","alert","unsubscribe","cancelled","startFirebaseOrCentralAuth","onAuthStateChanged","firebaseUser","authTokenProvider","injectedToken","_jsx","Provider","useUXTracking","tagUserSession","signupData","trackEvent","eventName","eventProperties","isProd","debug","logEvent","debug_mode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vertesia-ui-session.js","sources":["session/constants.js","session/auth/firebase.js","session/auth/composable.js","session/auth/useAuthState.js","session/auth/domainRouting.js","session/UserSession.js","session/auth/useCurrentTenant.js","session/UserSessionProvider.js","session/useUXTracking.js"],"sourcesContent":["export const LastSelectedAccountId_KEY = 'composableai.lastSelectedAccountId';\nexport const LastSelectedProjectId_KEY = 'composableai.lastSelectedProjectId';\n//# sourceMappingURL=constants.js.map","import { Env } from '@vertesia/ui/env';\nimport { getAnalytics } from 'firebase/analytics';\nimport { initializeApp } from 'firebase/app';\nimport { getAuth } from 'firebase/auth';\n// Use lazy initialization to avoid accessing Env before it's initialized\nlet _firebaseApp = null;\nlet _analytics = null;\nlet _firebaseAuth = null;\n// Getters that lazily initialize Firebase components when first accessed\nexport function getFirebaseApp() {\n if (!_firebaseApp) {\n try {\n if (!Env.firebase) {\n throw new Error('Firebase configuration is not available in the environment');\n }\n _firebaseApp = initializeApp(Env.firebase);\n }\n catch (error) {\n console.error('Failed to initialize Firebase app:', error);\n throw new Error('Firebase initialization failed - environment may not be properly initialized', {\n cause: error,\n });\n }\n }\n return _firebaseApp;\n}\nexport function getFirebaseAnalytics() {\n if (!_analytics) {\n _analytics = getAnalytics(getFirebaseApp());\n }\n return _analytics;\n}\nexport function getFirebaseAuth() {\n if (!_firebaseAuth) {\n _firebaseAuth = getAuth(getFirebaseApp());\n }\n return _firebaseAuth;\n}\nexport async function setFirebaseTenant(tenantEmail) {\n if (!tenantEmail) {\n console.log('No tenant name or email specified, skipping tenant setup');\n return;\n }\n if (!Env.firebase) {\n console.log('Firebase configuration is not available in the environment');\n return;\n }\n try {\n if (tenantEmail)\n console.log(`Resolving tenant ID from email: ${tenantEmail}`);\n // Add retry logic with exponential backoff\n let retries = 3;\n let retryDelay = 250; // Start with 250ms delay\n while (retries > 0) {\n try {\n // Call the API endpoint to resolve the tenant ID\n const response = await fetch('/api/resolve-tenant', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n tenantEmail: tenantEmail,\n }),\n // Add timeout to prevent hanging requests\n signal: AbortSignal.timeout(5000),\n });\n // Check for network errors\n if (!response) {\n throw new Error('No response received from tenant API');\n }\n // Handle HTTP error responses\n if (!response.ok) {\n // Try to parse the error response\n try {\n const errorData = await response.json();\n console.error('Failed to resolve tenant ID:', errorData.error);\n }\n catch {\n console.error(`Failed to resolve tenant ID: HTTP ${response.status}`);\n }\n // If the error is 404 Not Found, no need to retry\n if (response.status === 404) {\n console.warn(`Tenant not found for ${tenantEmail}`);\n return;\n }\n throw new Error(`HTTP error ${response.status}`);\n }\n // Successfully got a response, parse it\n const data = (await response.json());\n if (data?.firebaseTenantId) {\n const auth = getFirebaseAuth();\n auth.tenantId = data.firebaseTenantId;\n Env.firebase.providerType = data.provider ?? 'oidc';\n console.log(`Tenant ID set to ${auth.tenantId}`);\n return data;\n }\n else {\n console.error(`Invalid response format, missing tenantId for ${tenantEmail}`);\n return; // No need to retry for invalid response format\n }\n }\n catch (fetchError) {\n // Only retry for network-related errors\n if (retries > 1) {\n console.warn(`Tenant resolution failed, retrying in ${retryDelay}ms...`, fetchError);\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n retryDelay *= 2; // Exponential backoff\n retries--;\n }\n else {\n throw fetchError; // Last retry failed, propagate error\n }\n }\n }\n }\n catch (error) {\n // Final error handler\n console.error('Error setting Firebase tenant:', error instanceof Error ? error.message : 'Unknown error');\n // Continue without tenant ID - authentication will work without multi-tenancy\n // but the user will access the default tenant\n }\n}\nexport async function getFirebaseAuthToken(refresh) {\n const auth = getFirebaseAuth();\n const user = auth.currentUser;\n if (user) {\n return user\n .getIdToken(refresh)\n .then((token) => {\n Env.logger.info('Got Firebase token', {\n vertesia: {\n user_email: user.email,\n user_name: user.displayName,\n user_id: user.uid,\n refresh: refresh,\n },\n });\n return token;\n })\n .catch((err) => {\n Env.logger.error('Failed to get Firebase token', {\n vertesia: {\n user_email: user.email,\n user_name: user.displayName,\n user_id: user.uid,\n refresh: refresh,\n error: err,\n },\n });\n console.error('Failed to get access token', err);\n return null;\n });\n }\n else {\n Env.logger.warn('No user found');\n return Promise.resolve(null);\n }\n}\n//# sourceMappingURL=firebase.js.map","import { Env } from '@vertesia/ui/env';\nimport { jwtDecode } from 'jwt-decode';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from '../constants';\nimport { getFirebaseAuth, getFirebaseAuthToken } from './firebase';\nlet AUTH_TOKEN_RAW;\nlet AUTH_TOKEN;\nexport async function fetchComposableToken(getIdToken, accountId, projectId, ttl, retryCount = 0) {\n console.log(`Getting/refreshing composable token for account ${accountId} and project ${projectId} `);\n Env.logger.info('Getting/refreshing composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n retry_count: retryCount,\n },\n });\n const idToken = await getIdToken(); //get from firebase\n if (!idToken) {\n console.log('No id token found - using cookie auth');\n throw new Error('No id token found');\n }\n // Use STS endpoint - either configured or default to sts.vertesia.io\n const stsEndpoint = Env.endpoints.sts;\n console.log('Using STS for token generation:', stsEndpoint);\n Env.logger.info('Using STS for token generation', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n sts_url: stsEndpoint,\n },\n });\n try {\n // Call STS to generate a user token\n const stsUrl = new URL(`${stsEndpoint}/token/issue`);\n const requestBody = {\n type: 'user',\n account_id: accountId,\n project_id: projectId,\n expires_at: ttl ? Math.floor(Date.now() / 1000) + ttl : undefined,\n };\n const stsRes = await fetch(stsUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${idToken}`, // Firebase token for authentication\n },\n body: JSON.stringify(requestBody),\n }).catch((error) => {\n console.error('Failed to call STS endpoint', error);\n Env.logger.error('Failed to call STS endpoint', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: error,\n },\n });\n throw new STSError('Failed to call STS endpoint', stsEndpoint);\n });\n if (idToken && stsRes?.status === 404) {\n // User not found in token-server - call ensure-user endpoint\n console.log('404: User not found - calling ensure-user endpoint');\n Env.logger.info('404: User not found - calling ensure-user endpoint', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes?.status,\n },\n });\n const ensureResponse = await fetch(`${Env.endpoints.studio}/auth/ensure-user`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${idToken}`,\n 'Content-Type': 'application/json',\n },\n });\n if (ensureResponse.status === 412) {\n // No invite - trigger signup\n console.log('412: No invite found - signup required');\n Env.logger.info('412: No invite found - signup required', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n const idTokenDecoded = jwtDecode(idToken);\n if (!idTokenDecoded?.email) {\n Env.logger.error('No email found in id token');\n throw new Error('No email found in id token');\n }\n throw new UserNotFoundError('User not found - signup required', idTokenDecoded.email);\n }\n if (ensureResponse.status === 403) {\n // SigninScreen keys the invite-required view off this message.\n Env.logger.warn('403: Customer-domain user requires an invite to join', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n throw new Error('Customer-domain user requires an invite to join');\n }\n if (!ensureResponse.ok) {\n console.error('Failed to ensure user exists', ensureResponse.status);\n Env.logger.error('Failed to ensure user exists', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: ensureResponse.status,\n },\n });\n throw new Error('Failed to ensure user exists');\n }\n // User created/exists - retry token generation\n console.log('User ensured - retrying token generation');\n Env.logger.info('User ensured - retrying token generation', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n return fetchComposableToken(getIdToken, accountId, projectId, ttl, retryCount);\n }\n if (idToken && stsRes?.status === 412) {\n console.log(\"412: auth succeeded but user doesn't exist - signup required\", stsRes?.status);\n Env.logger.error(\"412: auth succeeded but user doesn't exist - signup required\", {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes?.status,\n },\n });\n const idTokenDecoded = jwtDecode(idToken);\n if (!idTokenDecoded?.email) {\n Env.logger.error('No email found in id token');\n throw new Error('No email found in id token');\n }\n Env.logger.error('User not found', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n email: idTokenDecoded.email,\n },\n });\n throw new UserNotFoundError('User not found', idTokenDecoded.email);\n }\n if (stsRes.status === 403) {\n // User doesn't have access to the requested account/project, or has no accounts\n // This can happen with:\n // 1. Stale localStorage from previous user\n // 2. User invited to a new account (doesn't have access yet)\n // 3. User exists but has no accounts at all\n if (retryCount > 0) {\n // Already retried without account scope - this is a real authorization failure\n console.error('403: Access denied even without account scope - user may have no accounts');\n Env.logger.error('403: Access denied after retry - authorization failure', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes.status,\n retry_count: retryCount,\n },\n });\n throw new Error('Access denied - user may not have access to any accounts');\n }\n console.log('403: Access denied - clearing cached account and retrying without account scope');\n Env.logger.warn('403: Access denied - clearing cached account and retrying', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: stsRes.status,\n retry_count: retryCount,\n },\n });\n // Clear any stale account/project from localStorage\n localStorage.removeItem(LastSelectedAccountId_KEY);\n if (accountId) {\n localStorage.removeItem(`${LastSelectedProjectId_KEY}-${accountId}`);\n }\n // Retry without account/project scope - let user log in to their default account\n return fetchComposableToken(getIdToken, undefined, undefined, ttl, retryCount + 1);\n }\n if (!stsRes.ok) {\n const errorText = await stsRes.text();\n console.error('STS token generation failed:', stsRes.status, errorText);\n Env.logger.error('STS token generation failed', {\n vertesia: {\n status: stsRes.status,\n error: errorText,\n account_id: accountId,\n project_id: projectId,\n },\n });\n throw new Error(`Failed to get token from STS: ${stsRes.status}`);\n }\n const { token } = await stsRes.json();\n console.log('Successfully got token from STS');\n Env.logger.info('Successfully got token from STS');\n return token;\n }\n catch (error) {\n if (error instanceof UserNotFoundError || error instanceof STSError) {\n throw error; // Re-throw UserNotFoundError and STSError to be handled separately in the caller\n }\n // Clear any stale account/project from localStorage on error\n localStorage.removeItem(LastSelectedAccountId_KEY);\n if (accountId) {\n localStorage.removeItem(`${LastSelectedProjectId_KEY}-${accountId}`);\n }\n console.error('Failed to get composable token from STS', error);\n Env.logger.error('Failed to get composable token from STS', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: error,\n },\n });\n throw new Error('Failed to get composable token', { cause: error });\n }\n}\n/**\n *\n * @param accountId\n * @param projectId\n * @param ttl time to live for the token in seconds\n * @returns\n */\nexport async function fetchComposableTokenFromFirebaseToken(accountId, projectId, ttl) {\n return fetchComposableToken(getFirebaseAuthToken, accountId, projectId, ttl);\n}\n/**\n * Mint a scoped Vertesia token from an existing Vertesia JWT. STS accepts STS-issued\n * tokens on /token/issue, so this works for sessions established via Central Auth where\n * the browser has no Firebase user.\n */\nexport async function fetchComposableTokenFromVertesiaToken(vertesiaToken, accountId, projectId, ttl) {\n return fetchComposableToken(() => Promise.resolve(vertesiaToken), accountId, projectId, ttl);\n}\n/** Returns the cached Vertesia raw JWT, if any. Does not refresh. */\nexport function getCurrentVertesiaToken() {\n return AUTH_TOKEN_RAW;\n}\nexport async function getComposableToken(accountId, projectId, initToken, forceRefresh = false, useInternalAuth = false) {\n const selectedAccount = accountId ?? localStorage.getItem(LastSelectedAccountId_KEY) ?? undefined;\n const selectedProject = projectId ?? localStorage.getItem(`${LastSelectedProjectId_KEY}-${selectedAccount}`) ?? undefined;\n //token is still valid for more than 5 minutes\n if (!forceRefresh && AUTH_TOKEN_RAW && AUTH_TOKEN && AUTH_TOKEN.exp > Date.now() / 1000 + 300) {\n return { rawToken: AUTH_TOKEN_RAW, token: AUTH_TOKEN, error: false };\n }\n //token is close to expire, refresh it\n if (!useInternalAuth && getFirebaseAuth().currentUser) {\n //we have a firebase user, get the token from there\n AUTH_TOKEN_RAW = await fetchComposableTokenFromFirebaseToken(selectedAccount, selectedProject);\n }\n else if (initToken || AUTH_TOKEN_RAW) {\n // we have a token already and no firebase user, refresh it\n AUTH_TOKEN_RAW = await fetchComposableToken(() => Promise.resolve(initToken ?? AUTH_TOKEN_RAW), selectedAccount, selectedProject);\n }\n if (!AUTH_TOKEN_RAW) {\n Env.logger.error('Cannot acquire a composable token', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n throw new Error('Cannot acquire a composable token');\n }\n AUTH_TOKEN = jwtDecode(AUTH_TOKEN_RAW);\n if (!AUTH_TOKEN?.exp || !AUTH_TOKEN_RAW) {\n console.error('Invalid composable token', AUTH_TOKEN);\n Env.logger.error('Invalid composable token', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n throw new Error('Invalid composable token');\n }\n return { rawToken: AUTH_TOKEN_RAW, token: AUTH_TOKEN, error: false };\n}\nexport class UserNotFoundError extends Error {\n email;\n constructor(message, email) {\n super(message);\n this.name = 'UserNotFoundError';\n this.email = email;\n }\n}\nexport class STSError extends Error {\n stsURL;\n constructor(message, stsURL) {\n super(message);\n this.name = 'STSError';\n this.stsURL = stsURL;\n }\n}\n//# sourceMappingURL=composable.js.map","/**\n * This hook is used to generate and verify state for OAuth2 authorization requests.\n * @returns\n */\nimport { useCallback } from 'react';\nconst AUTH_STATE_KEY = 'auth_state';\nconst STATE_EXPIRY_KEY = 'auth_state_expiry';\nconst STATE_TTL = 5 * 60 * 1000; // 5 min\nexport function useAuthState() {\n // Generate new state\n const generateState = useCallback(() => {\n const state = crypto.randomUUID();\n const expiryTime = Date.now() + STATE_TTL;\n // Store state and expiry\n sessionStorage.setItem(AUTH_STATE_KEY, state);\n sessionStorage.setItem(STATE_EXPIRY_KEY, expiryTime.toString());\n return state;\n }, []);\n // Verify returned state\n const verifyState = useCallback((returnedState) => {\n if (!returnedState) {\n return 'Missing state';\n }\n const savedState = sessionStorage.getItem(AUTH_STATE_KEY);\n const expiryTime = parseInt(sessionStorage.getItem(STATE_EXPIRY_KEY) || '0', 10);\n let reason;\n // Verify state matches and hasn't expired\n if (savedState !== returnedState) {\n reason = `State mismatched (${savedState} !== ${returnedState})`;\n }\n else if (Date.now() > expiryTime) {\n reason = 'State expired';\n }\n else {\n reason = undefined; // No errors\n }\n return reason;\n }, []);\n // Clear state (useful for cleanup)\n const clearState = useCallback(() => {\n sessionStorage.removeItem(AUTH_STATE_KEY);\n sessionStorage.removeItem(STATE_EXPIRY_KEY);\n }, []);\n return { generateState, verifyState, clearState };\n}\n//# sourceMappingURL=useAuthState.js.map","export function shouldUseFirebaseAuth(_hostname) {\n return window.AUTH_MODE === 'firebase';\n}\nexport function shouldRedirectToCentralAuth(_hostname) {\n return !shouldUseFirebaseAuth();\n}\n//# sourceMappingURL=domainRouting.js.map","import { VertesiaClient } from '@vertesia/client';\nimport { Env } from '@vertesia/ui/env';\nimport { jwtDecode } from 'jwt-decode';\nimport { createContext, useContext } from 'react';\nimport { getComposableToken } from './auth/composable';\nimport { shouldRedirectToCentralAuth } from './auth/domainRouting';\nimport { getFirebaseAuth } from './auth/firebase';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from './constants';\nexport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY };\nconst CENTRAL_AUTH_REDIRECT = 'https://internal-auth.vertesia.app/';\nclass UserSession {\n isLoading = true;\n client;\n authError;\n authToken;\n setSession;\n lastSelectedAccount;\n lastSelectedProject;\n onboardingComplete;\n constructor(client, setSession) {\n if (client) {\n this.client = client;\n }\n else {\n this.client = new VertesiaClient({\n serverUrl: Env.endpoints.studio,\n storeUrl: Env.endpoints.zeno,\n tokenServerUrl: Env.endpoints.sts,\n });\n }\n if (setSession) {\n this.setSession = setSession;\n }\n this.logout = this.logout.bind(this);\n }\n get store() {\n return this.client.store;\n }\n get user() {\n //compatibility\n return this.authToken;\n }\n get account() {\n //compatibility\n return this.authToken?.account;\n }\n get project() {\n return this.authToken?.project;\n }\n get accounts() {\n //compatibility\n return this.authToken?.accounts;\n }\n get authCallback() {\n return this.rawAuthToken.then((token) => `Bearer ${token}`);\n }\n get rawAuthToken() {\n return getComposableToken().then((res) => {\n const token = res?.rawToken;\n if (!token) {\n throw new Error('No token available');\n }\n this.authToken = jwtDecode(token);\n return token;\n });\n }\n signOut() {\n //compatibility\n this.logout();\n }\n getAccount() {\n return this.authToken?.account;\n }\n async login(token, options = {}) {\n this.authError = undefined;\n this.isLoading = false;\n this.client.withAuthCallback(() => this.authCallback);\n this.authToken = jwtDecode(token);\n console.log(`Logging in as ${this.authToken?.name} with account ${this.authToken?.account.name} (${this.authToken?.account.id}, and project ${this.authToken?.project?.name} (${this.authToken?.project?.id})`);\n //store selected account in local storage\n localStorage.setItem(LastSelectedAccountId_KEY, this.authToken.account.id);\n localStorage.setItem(`${LastSelectedProjectId_KEY}-${this.authToken.account.id}`, this.authToken.project?.id ?? '');\n // notify the host app of the login\n Env.onLogin?.(this.authToken);\n if (options.loadOnboardingStatus ?? true) {\n await this.fetchOnboardingStatus();\n }\n return Promise.resolve();\n }\n isLoggedIn() {\n return !!this.authToken;\n }\n logout() {\n console.log('Logging out');\n if (shouldRedirectToCentralAuth()) {\n // Redirect to central auth for logout\n // Central auth will handle Firebase logout\n console.log('Using central auth logout');\n this.authError = undefined;\n this.isLoading = false;\n this.authToken = undefined;\n this.setSession = undefined;\n this.client.withAuthCallback(undefined);\n const logoutUrl = new URL(CENTRAL_AUTH_REDIRECT);\n const currentUrl = new URL(window.location.href);\n currentUrl.hash = '';\n logoutUrl.pathname = '/logout';\n logoutUrl.searchParams.set('redirect_uri', currentUrl.toString());\n location.replace(logoutUrl.toString());\n }\n else {\n // Use Firebase logout directly\n console.log('Using Firebase logout');\n const wasLoggedIn = !!this.authToken;\n if (this.authToken) {\n void getFirebaseAuth().signOut();\n }\n this.authError = undefined;\n this.isLoading = false;\n this.authToken = undefined;\n this.setSession = undefined;\n this.client.withAuthCallback(undefined);\n // Navigate to root to avoid React rendering errors when\n // unmounting deeply nested route components during logout.\n // Only navigate if user was actually logged in to avoid\n // infinite reload loop on fresh/incognito sessions.\n if (wasLoggedIn) {\n location.replace('/');\n }\n }\n }\n async switchAccount(targetAccountId) {\n localStorage.setItem(LastSelectedAccountId_KEY, targetAccountId);\n if (this) {\n if (this.account && this.project) {\n localStorage.setItem(`${LastSelectedProjectId_KEY}-${this.account.id}`, this.project.id);\n }\n else if (this.account) {\n localStorage.removeItem(`${LastSelectedProjectId_KEY}-${this.account.id}`);\n }\n }\n window.location.replace(`/?a=${targetAccountId}`);\n }\n async switchProject(targetProjectId) {\n if (this.account) {\n localStorage.setItem(`${LastSelectedProjectId_KEY}-${this.account.id}`, targetProjectId);\n }\n window.location.replace(`/?a=${this.account?.id}&p=${targetProjectId}`);\n }\n async fetchAccounts() {\n return this.client.accounts\n .list()\n .then((accounts) => {\n if (!this.authToken) {\n throw new Error('No token available');\n }\n this.authToken.accounts = accounts;\n this.setSession?.(this.clone());\n })\n .catch((err) => {\n console.error('Failed to fetch accounts', err);\n throw err;\n });\n }\n async fetchProjects(accountId) {\n return this.client.projects\n .list([accountId])\n .then((projects) => {\n if (!this.authToken) {\n throw new Error('No token available');\n }\n this.authToken = {\n ...this.authToken,\n accounts: this.authToken.accounts?.map((account) => {\n if (account.id === accountId) {\n return {\n ...account,\n projects: projects.filter((project) => project.account === accountId),\n };\n }\n return account;\n }),\n };\n this.setSession?.(this.clone());\n })\n .catch((err) => {\n console.error('Failed to fetch projects', err);\n throw err;\n });\n }\n async fetchOnboardingStatus() {\n if (this.onboardingComplete) {\n console.log('Onboarding already completed');\n return false;\n }\n const previousStatus = this.onboardingComplete;\n try {\n const onboarding = await this.client.account.onboardingProgress();\n this.onboardingComplete = Object.values(onboarding).every((value) => value === true);\n if (previousStatus !== this.onboardingComplete) {\n return true;\n }\n this.setSession?.(this.clone());\n }\n catch (error) {\n console.error('Error fetching onboarding status:', error);\n this.onboardingComplete = false;\n this.setSession?.(this.clone());\n }\n return false;\n }\n clone() {\n const session = new UserSession(this.client);\n session.isLoading = this.isLoading;\n session.authError = this.authError;\n session.authToken = this.authToken;\n session.setSession = this.setSession;\n session.lastSelectedAccount = this.lastSelectedAccount;\n session.switchAccount = this.switchAccount;\n session.onboardingComplete = this.onboardingComplete;\n return session;\n }\n}\nconst UserSessionContext = createContext(undefined);\nexport function useUserSession() {\n const session = useContext(UserSessionContext);\n if (!session) {\n throw new Error('useUserSession must be used within a UserSessionProvider');\n }\n return session;\n}\nexport { UserSession, UserSessionContext };\n//# sourceMappingURL=UserSession.js.map","import { i18nInstance, NAMESPACE } from '@vertesia/ui/i18n';\nimport { useEffect, useState } from 'react';\nimport { useUserSession } from '../UserSession';\nexport function useCurrentTenant() {\n const { user } = useUserSession();\n const [currentTenant, setCurrentTenant] = useState(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState(null);\n useEffect(() => {\n const loadCurrentTenant = async () => {\n if (!user?.email) {\n setCurrentTenant(null);\n setIsLoading(false);\n return;\n }\n try {\n const response = await fetch('/api/resolve-tenant', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n tenantEmail: user.email,\n }),\n });\n if (response.ok) {\n const tenantData = await response.json();\n if (tenantData) {\n // Convert the resolved tenant data to our TenantConfig format\n setCurrentTenant({\n tenantKey: tenantData.name || 'unknown',\n name: tenantData.label || tenantData.name || 'Unknown',\n domain: tenantData.domain || [],\n firebaseTenantId: tenantData.firebaseTenantId,\n provider: tenantData.provider,\n logo: tenantData.logo,\n });\n }\n else {\n setCurrentTenant(null);\n }\n }\n else {\n setCurrentTenant(null);\n }\n }\n catch (error) {\n console.error('Error loading current tenant:', error);\n setError(i18nInstance.getFixedT(null, NAMESPACE)('errors.failedToLoadTenantConfig'));\n setCurrentTenant(null);\n }\n finally {\n setIsLoading(false);\n }\n };\n void loadCurrentTenant();\n }, [user?.email]);\n return {\n currentTenant,\n isLoading,\n error,\n };\n}\n//# sourceMappingURL=useCurrentTenant.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { Env } from '@vertesia/ui/env';\nimport { onAuthStateChanged } from 'firebase/auth';\nimport { useEffect, useRef, useState } from 'react';\nimport { getComposableToken, STSError, UserNotFoundError } from './auth/composable';\nimport { shouldRedirectToCentralAuth } from './auth/domainRouting';\nimport { getFirebaseAuth } from './auth/firebase';\nimport { useAuthState } from './auth/useAuthState';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY, UserSession, UserSessionContext } from './UserSession';\nconst CENTRAL_AUTH_REDIRECT = 'https://internal-auth.vertesia.app/';\nexport function UserSessionProvider({ children, loadOnboardingStatus = true }) {\n const hashParams = new URLSearchParams(location.hash.substring(1));\n const token = hashParams.get('token');\n const state = hashParams.get('state');\n const [session, setSession] = useState(new UserSession());\n const { generateState, verifyState, clearState } = useAuthState();\n const hasInitiatedAuthRef = useRef(false);\n const authFlowRef = useRef(undefined);\n const redirectToCentralAuth = (projectId, accountId) => {\n const url = new URL(`${CENTRAL_AUTH_REDIRECT}?sts=${Env.endpoints.sts ?? 'https://sts.vertesia.io'}`);\n const currentUrl = new URL(window.location.href);\n currentUrl.hash = '';\n if (projectId)\n currentUrl.searchParams.set('p', projectId);\n if (accountId)\n currentUrl.searchParams.set('a', accountId);\n url.searchParams.set('redirect_uri', currentUrl.toString());\n url.searchParams.set('state', generateState());\n location.replace(url.toString());\n };\n authFlowRef.current = () => {\n // Make this effect idempotent - only run auth flow once\n if (hasInitiatedAuthRef.current) {\n console.log('Auth: skipping duplicate auth flow initiation');\n return;\n }\n hasInitiatedAuthRef.current = true;\n console.log('Auth: starting auth flow');\n Env.logger.info('Starting auth flow');\n const currentUrl = new URL(window.location.href);\n const selectedAccount = currentUrl.searchParams.get('a') ?? localStorage.getItem(LastSelectedAccountId_KEY) ?? undefined;\n const selectedProject = currentUrl.searchParams.get('p') ??\n localStorage.getItem(`${LastSelectedProjectId_KEY}-${selectedAccount}`) ??\n undefined;\n console.log('Auth: selected account', selectedAccount);\n console.log('Auth: selected project', selectedProject);\n Env.logger.info('Selected account and project', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n if (token && state) {\n session.setSession = setSession;\n const validationError = verifyState(state);\n if (validationError) {\n console.error(`Auth: invalid state: ${validationError}`);\n Env.logger.error(`Invalid state: ${validationError}`, {\n vertesia: {\n state: state,\n },\n });\n redirectToCentralAuth();\n }\n else {\n clearState();\n }\n getComposableToken(selectedAccount, selectedProject, token, false, shouldRedirectToCentralAuth())\n .then((res) => {\n session.login(res.rawToken, { loadOnboardingStatus }).then(() => {\n setSession(session.clone());\n //cleanup the hash\n window.location.hash = '';\n });\n })\n .catch((err) => {\n // Don't redirect to central auth for UserNotFoundError - let signup flow handle it\n if (err instanceof UserNotFoundError) {\n console.log('User not found - will trigger signup flow', err);\n session.isLoading = false;\n session.authError = err;\n setSession(session.clone());\n return;\n }\n if (err instanceof STSError) {\n console.error('STS error during token exchange', err);\n Env.logger.error('STS error during token exchange', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n sts_url: err.stsURL,\n error: err,\n },\n });\n window.alert('Authentication failed due to an issue with the authentication service. Please try again later.');\n session.logout();\n setSession(session.clone());\n window.location.hash = '';\n return;\n }\n console.error('Failed to fetch user token from studio, redirecting to central auth', err);\n Env.logger.error('Failed to fetch user token from studio, redirecting to central auth', {\n vertesia: {\n error: err,\n },\n });\n redirectToCentralAuth();\n });\n return;\n }\n else {\n // If the current host is not in the Firebase allowlist, central auth owns sign-in.\n if (!session.isLoggedIn()) {\n console.log('Auth: not logged in & no token/state');\n Env.logger.info('Not logged in & no token/state', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n if (shouldRedirectToCentralAuth()) {\n console.log('Auth: host is not in Firebase auth allowlist, redirecting to central auth with selection', selectedAccount, selectedProject);\n Env.logger.info('Redirecting to central auth with selection', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n redirectToCentralAuth();\n return; // Don't register onAuthStateChanged listener when redirecting\n }\n else {\n console.log('Auth: host is in Firebase auth allowlist');\n Env.logger.info('Host is in Firebase auth allowlist', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n }\n }\n }\n return onAuthStateChanged(getFirebaseAuth(), async (firebaseUser) => {\n if (firebaseUser) {\n console.log('Auth: successful login with firebase');\n Env.logger.info('Successful login with firebase', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n session.setSession = setSession;\n await getComposableToken(selectedAccount, selectedProject, undefined, false, shouldRedirectToCentralAuth())\n .then((res) => {\n session.login(res.rawToken, { loadOnboardingStatus }).then(() => setSession(session.clone()));\n })\n .catch((err) => {\n console.error('Failed to fetch user token from studio', err);\n Env.logger.error('Failed to fetch user token from studio', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n error: err,\n },\n });\n if (!(err instanceof UserNotFoundError))\n session.logout();\n session.isLoading = false;\n session.authError = err;\n setSession(session.clone());\n });\n }\n else {\n // anonymous user\n console.log('Auth: using anonymous user');\n Env.logger.info('Using anonymous user', {\n vertesia: {\n account_id: selectedAccount,\n project_id: selectedProject,\n },\n });\n session.client.withAuthCallback(undefined);\n session.logout();\n setSession(session.clone());\n }\n });\n };\n useEffect(() => {\n return authFlowRef.current?.();\n }, []);\n return _jsx(UserSessionContext.Provider, { value: session, children: children });\n}\n//# sourceMappingURL=UserSessionProvider.js.map","import { Env } from '@vertesia/ui/env';\nimport { logEvent } from 'firebase/analytics';\nimport { getFirebaseAnalytics } from './auth/firebase';\nexport function useUXTracking() {\n //identify user in monitoring and UX systems\n const tagUserSession = async (user) => {\n const signupData = window.localStorage.getItem('composableSignupData');\n if (!user) {\n console.error('No user found -- skipping tagging');\n return;\n }\n if (signupData) {\n window.localStorage.removeItem('composableSignupData');\n }\n };\n //send event to analytics and UX systems\n const trackEvent = (eventName, eventProperties) => {\n if (!Env.isProd) {\n console.debug('track event', eventName, eventProperties);\n }\n //GA via firebase\n logEvent(getFirebaseAnalytics(), eventName, { ...eventProperties, debug_mode: !Env.isProd });\n };\n return {\n tagUserSession,\n trackEvent,\n };\n}\n//# sourceMappingURL=useUXTracking.js.map"],"names":["LastSelectedAccountId_KEY","LastSelectedProjectId_KEY","AUTH_TOKEN_RAW","AUTH_TOKEN","_firebaseApp","_analytics","_firebaseAuth","getFirebaseApp","Env","firebase","Error","initializeApp","error","console","cause","getFirebaseAnalytics","getAnalytics","getFirebaseAuth","getAuth","async","setFirebaseTenant","tenantEmail","log","retries","retryDelay","response","fetch","method","headers","body","JSON","stringify","signal","AbortSignal","timeout","ok","errorData","json","status","warn","data","firebaseTenantId","auth","tenantId","providerType","provider","fetchError","Promise","resolve","setTimeout","message","getFirebaseAuthToken","refresh","user","currentUser","getIdToken","then","token","logger","info","vertesia","user_email","email","user_name","displayName","user_id","uid","catch","err","fetchComposableToken","accountId","projectId","ttl","retryCount","account_id","project_id","retry_count","idToken","stsEndpoint","endpoints","sts","sts_url","stsUrl","URL","requestBody","type","expires_at","Math","floor","Date","now","undefined","stsRes","Authorization","STSError","ensureResponse","studio","idTokenDecoded","jwtDecode","UserNotFoundError","localStorage","removeItem","errorText","text","fetchComposableTokenFromFirebaseToken","fetchComposableTokenFromVertesiaToken","vertesiaToken","getCurrentVertesiaToken","getComposableToken","initToken","forceRefresh","useInternalAuth","selectedAccount","getItem","selectedProject","exp","rawToken","constructor","super","this","name","stsURL","AUTH_STATE_KEY","STATE_EXPIRY_KEY","useAuthState","generateState","useCallback","state","crypto","randomUUID","expiryTime","sessionStorage","setItem","toString","verifyState","returnedState","savedState","parseInt","reason","clearState","shouldRedirectToCentralAuth","_hostname","window","AUTH_MODE","UserSession","isLoading","client","authError","authToken","setSession","lastSelectedAccount","lastSelectedProject","onboardingComplete","VertesiaClient","serverUrl","storeUrl","zeno","tokenServerUrl","logout","bind","store","account","project","accounts","authCallback","rawAuthToken","res","signOut","getAccount","login","options","withAuthCallback","id","onLogin","loadOnboardingStatus","fetchOnboardingStatus","isLoggedIn","logoutUrl","currentUrl","location","href","hash","pathname","searchParams","set","replace","wasLoggedIn","switchAccount","targetAccountId","switchProject","targetProjectId","fetchAccounts","list","clone","fetchProjects","projects","map","filter","previousStatus","onboarding","onboardingProgress","Object","values","every","value","session","UserSessionContext","createContext","useUserSession","useContext","useCurrentTenant","currentTenant","setCurrentTenant","useState","setIsLoading","setError","useEffect","tenantData","tenantKey","label","domain","logo","i18nInstance","getFixedT","NAMESPACE","loadCurrentTenant","UserSessionProvider","children","hashParams","URLSearchParams","substring","get","hasInitiatedAuthRef","useRef","authFlowRef","redirectToCentralAuth","url","current","validationError","alert","onAuthStateChanged","firebaseUser","_jsx","Provider","useUXTracking","tagUserSession","signupData","trackEvent","eventName","eventProperties","isProd","debug","logEvent","debug_mode"],"mappings":"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"}
|