@vertesia/ui 0.65.0 → 0.67.0
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/esm/core/components/EmptyCollection.js +2 -2
- package/lib/esm/core/components/EmptyCollection.js.map +1 -1
- package/lib/esm/core/components/InputList.js +2 -2
- package/lib/esm/core/components/InputList.js.map +1 -1
- package/lib/esm/core/components/SidePanel.js +1 -1
- package/lib/esm/core/components/SidePanel.js.map +1 -1
- package/lib/esm/core/components/Switch.js +2 -2
- package/lib/esm/core/components/Switch.js.map +1 -1
- package/lib/esm/core/components/shadcn/calendar.js +0 -1
- package/lib/esm/core/components/shadcn/calendar.js.map +1 -1
- package/lib/esm/core/components/shadcn/checkbox.js +0 -1
- package/lib/esm/core/components/shadcn/checkbox.js.map +1 -1
- package/lib/esm/core/components/shadcn/command.js +0 -1
- package/lib/esm/core/components/shadcn/command.js.map +1 -1
- package/lib/esm/core/components/shadcn/dialog.js +0 -1
- package/lib/esm/core/components/shadcn/dialog.js.map +1 -1
- package/lib/esm/core/components/shadcn/filters/comboBox.js +18 -0
- package/lib/esm/core/components/shadcn/filters/comboBox.js.map +1 -1
- package/lib/esm/core/components/shadcn/filters/filterBar.js +38 -17
- package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/esm/core/components/shadcn/filters/filters.js +11 -5
- package/lib/esm/core/components/shadcn/filters/filters.js.map +1 -1
- package/lib/esm/core/components/shadcn/filters/selectFilter.js +1 -1
- package/lib/esm/core/components/shadcn/filters/selectFilter.js.map +1 -1
- package/lib/esm/core/components/shadcn/filters/stringListFilter.js +24 -0
- package/lib/esm/core/components/shadcn/filters/stringListFilter.js.map +1 -0
- package/lib/esm/core/components/shadcn/filters/textFilter.js +2 -1
- package/lib/esm/core/components/shadcn/filters/textFilter.js.map +1 -1
- package/lib/esm/core/components/shadcn/label.js +0 -1
- package/lib/esm/core/components/shadcn/label.js.map +1 -1
- package/lib/esm/features/agent/PayloadBuilder.js +27 -0
- package/lib/esm/features/agent/PayloadBuilder.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentConversation.js +1 -1
- package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js +3 -3
- package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/esm/features/facets/VEnvironmentFacet.js +24 -0
- package/lib/esm/features/facets/VEnvironmentFacet.js.map +1 -0
- package/lib/esm/features/facets/VFacetsNav.js +69 -26
- package/lib/esm/features/facets/VFacetsNav.js.map +1 -1
- package/lib/esm/features/facets/VInteractionFacet.js +45 -0
- package/lib/esm/features/facets/VInteractionFacet.js.map +1 -0
- package/lib/esm/features/facets/VStringFacet.js +6 -5
- package/lib/esm/features/facets/VStringFacet.js.map +1 -1
- package/lib/esm/features/facets/VUserFacet.js +6 -6
- package/lib/esm/features/facets/VUserFacet.js.map +1 -1
- package/lib/esm/features/layout/GenericPageNavHeader.js +1 -1
- package/lib/esm/features/magic-pdf/TextPageView.js +1 -2
- package/lib/esm/features/magic-pdf/TextPageView.js.map +1 -1
- package/lib/esm/features/store/collections/CollectionsTable.js +9 -5
- package/lib/esm/features/store/collections/CollectionsTable.js.map +1 -1
- package/lib/esm/features/store/collections/{CollectionsView.js → CreateCollection.js} +6 -14
- package/lib/esm/features/store/collections/CreateCollection.js.map +1 -0
- package/lib/esm/features/store/collections/EditCollectionView.js +1 -1
- package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
- package/lib/esm/features/store/collections/SelectCollection.js +24 -0
- package/lib/esm/features/store/collections/SelectCollection.js.map +1 -0
- package/lib/esm/features/store/collections/index.js +2 -2
- package/lib/esm/features/store/collections/index.js.map +1 -1
- package/lib/esm/features/store/objects/DocumentSearchResults.js +6 -3
- package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/esm/features/store/objects/components/ContentOverview.js +17 -16
- package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/esm/features/store/objects/components/DocumentIcon.js +7 -10
- package/lib/esm/features/store/objects/components/DocumentIcon.js.map +1 -1
- package/lib/esm/features/store/objects/components/DocumentInput.js +1 -2
- package/lib/esm/features/store/objects/components/DocumentInput.js.map +1 -1
- package/lib/esm/features/store/objects/components/PropertiesEditorModal.js +4 -2
- package/lib/esm/features/store/objects/components/PropertiesEditorModal.js.map +1 -1
- package/lib/esm/features/store/objects/components/SaveVersionConfirmModal.js +1 -2
- package/lib/esm/features/store/objects/components/SaveVersionConfirmModal.js.map +1 -1
- package/lib/esm/features/store/objects/components/SelectDocument.js +9 -3
- package/lib/esm/features/store/objects/components/SelectDocument.js.map +1 -1
- package/lib/esm/features/store/objects/components/SelectDocumentModal.js +2 -2
- package/lib/esm/features/store/objects/components/SelectDocumentModal.js.map +1 -1
- package/lib/esm/features/store/objects/layout/documentLayout.js +2 -2
- package/lib/esm/features/store/objects/layout/documentLayout.js.map +1 -1
- package/lib/esm/features/store/objects/search/DocumentSearchContext.js +4 -2
- package/lib/esm/features/store/objects/search/DocumentSearchContext.js.map +1 -1
- package/lib/esm/features/store/objects/selection/SelectionActions.js +1 -1
- package/lib/esm/features/store/objects/selection/SelectionActions.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js +7 -10
- package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/ChangeTypeAction.js +1 -1
- package/lib/esm/features/store/objects/selection/actions/ChangeTypeAction.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/DeleteObjectsAction.js +2 -2
- package/lib/esm/features/store/objects/selection/actions/DeleteObjectsAction.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/ExportPropertiesAction.js +1 -1
- package/lib/esm/features/store/objects/selection/actions/ExportPropertiesAction.js.map +1 -1
- package/lib/esm/features/store/objects/selection/actions/RemoveFromCollectionAction.js +1 -1
- package/lib/esm/features/store/objects/selection/actions/RemoveFromCollectionAction.js.map +1 -1
- package/lib/esm/features/store/types/ContentObjectTypesSearch.js +2 -3
- package/lib/esm/features/store/types/ContentObjectTypesSearch.js.map +1 -1
- package/lib/esm/features/store/types/ContentObjectTypesTable.js +1 -1
- package/lib/esm/features/store/types/ContentObjectTypesTable.js.map +1 -1
- package/lib/esm/features/store/types/CreateOrUpdateTypeModal.js +2 -2
- package/lib/esm/features/store/types/CreateOrUpdateTypeModal.js.map +1 -1
- package/lib/esm/features/store/types/ObjectSchemaEditor.js +2 -3
- package/lib/esm/features/store/types/ObjectSchemaEditor.js.map +1 -1
- package/lib/esm/features/store/types/TableLayoutEditor.js +1 -1
- package/lib/esm/features/store/types/TableLayoutEditor.js.map +1 -1
- package/lib/esm/features/store/types/index.js +0 -2
- package/lib/esm/features/store/types/index.js.map +1 -1
- package/lib/esm/features/user/UserInfo.js +1 -2
- package/lib/esm/features/user/UserInfo.js.map +1 -1
- package/lib/esm/features/utils/rendition.js +22 -2
- package/lib/esm/features/utils/rendition.js.map +1 -1
- package/lib/esm/layout/FullHeightLayout.js +2 -4
- package/lib/esm/layout/FullHeightLayout.js.map +1 -1
- package/lib/esm/session/UserSession.js +2 -2
- package/lib/esm/session/UserSession.js.map +1 -1
- package/lib/esm/session/auth/composable.js +1 -1
- package/lib/esm/session/auth/composable.js.map +1 -1
- package/lib/esm/session/constants.js +3 -0
- package/lib/esm/session/constants.js.map +1 -0
- package/lib/esm/widgets/codemirror/CodeMirrorEditor.js +2 -2
- package/lib/esm/widgets/codemirror/CodeMirrorEditor.js.map +1 -1
- package/lib/esm/widgets/properties/PropertiesView.js +4 -2
- package/lib/esm/widgets/properties/PropertiesView.js.map +1 -1
- package/lib/esm/widgets/schema-editor/editor/SchemaEditor.js +1 -1
- package/lib/esm/widgets/schema-editor/editor/SchemaEditor.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/core/components/InputList.d.ts +2 -1
- package/lib/types/core/components/Switch.d.ts +2 -1
- package/lib/types/core/components/shadcn/filters/comboBox.d.ts +5 -0
- package/lib/types/core/components/shadcn/filters/stringListFilter.d.ts +10 -0
- package/lib/types/core/components/shadcn/filters/types.d.ts +3 -3
- package/lib/types/features/agent/PayloadBuilder.d.ts +8 -1
- package/lib/types/features/facets/VEnvironmentFacet.d.ts +11 -0
- package/lib/types/features/facets/VFacetsNav.d.ts +9 -1
- package/lib/types/features/facets/VInteractionFacet.d.ts +14 -0
- package/lib/types/features/facets/VStringFacet.d.ts +3 -2
- package/lib/types/features/facets/VUserFacet.d.ts +3 -2
- package/lib/types/features/store/collections/{CollectionsView.d.ts → CreateCollection.d.ts} +5 -3
- package/lib/types/features/store/collections/SelectCollection.d.ts +14 -0
- package/lib/types/features/store/collections/index.d.ts +2 -2
- package/lib/types/features/store/objects/components/ContentOverview.d.ts +2 -1
- package/lib/types/features/store/objects/components/DocumentIcon.d.ts +2 -1
- package/lib/types/features/store/objects/components/PropertiesEditorModal.d.ts +2 -1
- package/lib/types/features/store/objects/layout/documentLayout.d.ts +1 -1
- package/lib/types/features/store/objects/search/DocumentSearchContext.d.ts +3 -2
- package/lib/types/features/store/objects/selection/actions/DeleteObjectsAction.d.ts +2 -1
- package/lib/types/features/store/objects/selection/actions/RemoveFromCollectionAction.d.ts +2 -1
- package/lib/types/features/store/types/index.d.ts +0 -2
- package/lib/types/features/utils/rendition.d.ts +1 -1
- package/lib/types/session/UserSession.d.ts +2 -2
- package/lib/types/session/constants.d.ts +2 -0
- package/lib/vertesia-ui-core.js +1 -1
- package/lib/vertesia-ui-core.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-layout.js +1 -1
- package/lib/vertesia-ui-layout.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-widgets.js +1 -1
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/package.json +4 -4
- package/src/core/components/EmptyCollection.tsx +26 -24
- package/src/core/components/InputList.tsx +3 -1
- package/src/core/components/SidePanel.tsx +2 -2
- package/src/core/components/Switch.tsx +4 -3
- package/src/core/components/shadcn/calendar.tsx +0 -2
- package/src/core/components/shadcn/checkbox.tsx +0 -2
- package/src/core/components/shadcn/command.tsx +0 -2
- package/src/core/components/shadcn/dialog.tsx +0 -2
- package/src/core/components/shadcn/filters/comboBox.tsx +73 -0
- package/src/core/components/shadcn/filters/filterBar.tsx +41 -17
- package/src/core/components/shadcn/filters/filters.tsx +30 -14
- package/src/core/components/shadcn/filters/selectFilter.tsx +3 -3
- package/src/core/components/shadcn/filters/stringListFilter.tsx +58 -0
- package/src/core/components/shadcn/filters/textFilter.tsx +2 -1
- package/src/core/components/shadcn/filters/types.ts +3 -3
- package/src/core/components/shadcn/label.tsx +0 -2
- package/src/features/agent/PayloadBuilder.tsx +34 -1
- package/src/features/agent/chat/ModernAgentConversation.tsx +639 -639
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +12 -13
- package/src/features/facets/VEnvironmentFacet.tsx +42 -0
- package/src/features/facets/VFacetsNav.tsx +87 -29
- package/src/features/facets/VInteractionFacet.tsx +73 -0
- package/src/features/facets/VStringFacet.tsx +7 -6
- package/src/features/facets/VUserFacet.tsx +7 -6
- package/src/features/layout/GenericPageNavHeader.tsx +1 -1
- package/src/features/magic-pdf/TextPageView.tsx +1 -2
- package/src/features/store/collections/CollectionsTable.tsx +49 -40
- package/src/features/store/collections/{CollectionsView.tsx → CreateCollection.tsx} +15 -42
- package/src/features/store/collections/EditCollectionView.tsx +1 -1
- package/src/features/store/collections/SelectCollection.tsx +46 -0
- package/src/features/store/collections/index.ts +2 -2
- package/src/features/store/objects/DocumentSearchResults.tsx +6 -3
- package/src/features/store/objects/components/ContentOverview.tsx +38 -98
- package/src/features/store/objects/components/DocumentIcon.tsx +27 -14
- package/src/features/store/objects/components/DocumentInput.tsx +1 -2
- package/src/features/store/objects/components/PropertiesEditorModal.tsx +7 -3
- package/src/features/store/objects/components/SaveVersionConfirmModal.tsx +2 -2
- package/src/features/store/objects/components/SelectDocument.tsx +18 -3
- package/src/features/store/objects/components/SelectDocumentModal.tsx +6 -6
- package/src/features/store/objects/layout/documentLayout.tsx +2 -2
- package/src/features/store/objects/search/DocumentSearchContext.ts +6 -3
- package/src/features/store/objects/selection/ObjectsActionContext.tsx +1 -1
- package/src/features/store/objects/selection/SelectionActions.tsx +0 -1
- package/src/features/store/objects/selection/actions/AddToCollectionAction.tsx +10 -21
- package/src/features/store/objects/selection/actions/ChangeTypeAction.tsx +1 -1
- package/src/features/store/objects/selection/actions/DeleteObjectsAction.tsx +2 -2
- package/src/features/store/objects/selection/actions/ExportPropertiesAction.tsx +1 -1
- package/src/features/store/objects/selection/actions/RemoveFromCollectionAction.tsx +1 -1
- package/src/features/store/types/ContentObjectTypesSearch.tsx +3 -4
- package/src/features/store/types/ContentObjectTypesTable.tsx +3 -1
- package/src/features/store/types/CreateOrUpdateTypeModal.tsx +2 -9
- package/src/features/store/types/ObjectSchemaEditor.tsx +4 -5
- package/src/features/store/types/TableLayoutEditor.tsx +4 -4
- package/src/features/store/types/index.ts +0 -2
- package/src/features/user/UserInfo.tsx +1 -2
- package/src/features/utils/rendition.ts +23 -1
- package/src/layout/FullHeightLayout.tsx +2 -2
- package/src/session/UserSession.ts +2 -2
- package/src/session/auth/composable.ts +1 -1
- package/src/session/constants.ts +2 -0
- package/src/widgets/codemirror/CodeMirrorEditor.tsx +2 -2
- package/src/widgets/properties/PropertiesView.tsx +10 -2
- package/src/widgets/schema-editor/editor/SchemaEditor.tsx +1 -1
- package/lib/esm/features/store/collections/CollectionView.js +0 -53
- package/lib/esm/features/store/collections/CollectionView.js.map +0 -1
- package/lib/esm/features/store/collections/CollectionsView.js.map +0 -1
- package/lib/esm/features/store/types/ContentObjectTypeView.js +0 -158
- package/lib/esm/features/store/types/ContentObjectTypeView.js.map +0 -1
- package/lib/esm/features/store/types/ContentObjectTypesView.js +0 -55
- package/lib/esm/features/store/types/ContentObjectTypesView.js.map +0 -1
- package/lib/types/features/store/collections/CollectionView.d.ts +0 -5
- package/lib/types/features/store/types/ContentObjectTypeView.d.ts +0 -5
- package/lib/types/features/store/types/ContentObjectTypesView.d.ts +0 -8
- package/src/features/store/collections/CollectionView.tsx +0 -94
- package/src/features/store/types/ContentObjectTypeView.tsx +0 -244
- package/src/features/store/types/ContentObjectTypesView.tsx +0 -71
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as e,jsxs as l,Fragment as r}from"react/jsx-runtime";import i from"clsx";import{Transition as t,Dialog as n,TransitionChild as a,DialogPanel as s}from"@headlessui/react";import{Menu as o,Search as c,Dot as d,X as h}from"lucide-react";import{createContext as m,useContext as u,useState as f,useEffect as x,Fragment as g}from"react";import{Button as p,TooltipProvider as v,Tooltip as N,TooltipTrigger as b,TooltipContent as w}from"@vertesia/ui/core";import{Nav as y}from"@vertesia/ui/router";function k({className:l,children:r}){return e("div",{className:i("flex flex-col","h-full","overflow-y-auto",l),children:r})}k.Fixed=function({heightClass:l,className:r,children:t}){return e("div",{className:i("w-full",l,r),children:t})},k.Body=function({className:l,children:r}){return e("div",{className:i("grow overflow-auto","min-h-0","
|
|
1
|
+
import{jsx as e,jsxs as l,Fragment as r}from"react/jsx-runtime";import i from"clsx";import{Transition as t,Dialog as n,TransitionChild as a,DialogPanel as s}from"@headlessui/react";import{Menu as o,Search as c,Dot as d,X as h}from"lucide-react";import{createContext as m,useContext as u,useState as f,useEffect as x,Fragment as g}from"react";import{Button as p,TooltipProvider as v,Tooltip as N,TooltipTrigger as b,TooltipContent as w}from"@vertesia/ui/core";import{Nav as y}from"@vertesia/ui/router";function k({className:l,children:r}){return e("div",{className:i("flex flex-col","h-full","overflow-y-auto","px-2",l),children:r})}k.Fixed=function({heightClass:l,className:r,children:t}){return e("div",{className:i("w-full",l,r),children:t})},k.Body=function({className:l,children:r}){return e("div",{className:i("grow overflow-auto","min-h-0","p-2",l),children:r})},k.VR=function({}){return e("div",{className:"w-[1px] border border-red-200"})},k.HR=function({}){return e("div",{className:"w-full h-1 border-b border-red-200"})};const C=m({isOpen:!1,toggleMobile:()=>{},toggleDesktop:()=>{}});function S(){return u(C)}function z({title:l}){return e("div",{className:"self-center text-lg font-semibold",children:l})}function O({children:r,logo:i,onSearch:t,title:n}){return l("div",{className:"sticky top-0 z-40 flex h-16 shrink-0 items-center gap-x-4 border-b px-4 shadow-2xs sm:gap-x-6 sm:px-6 lg:px-8",children:[e(T,{}),e("div",{className:"lg:hidden",children:i}),t&&e(D,{visible:"mobile"}),l("div",{className:"flex flex-1 gap-x-4 self-stretch lg:gap-x-6",children:[e(z,{title:n}),t&&e(F,{onSearch:t}),e("div",{className:"flex items-center gap-x-4 lg:gap-x-6 ml-auto",children:r})]})]})}function F({}){return l("form",{className:"relative flex flex-1",action:"#",method:"GET",children:[e("label",{htmlFor:"search-field",className:"sr-only",children:"Search"}),e(c,{className:"pointer-events-none absolute inset-y-0 left-0 h-full w-5 text-gray-400","aria-hidden":"true"}),e("input",{id:"search-field",className:"block h-full w-full border-0 py-0 pl-8 pr-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm",placeholder:"Search...",type:"search",name:"search"})]})}function T(){const{toggleDesktop:l,toggleMobile:i}=S();return e(r,{children:e(p,{variant:"ghost",size:"icon",onClick:()=>{window.innerWidth<1024?i():l()},className:"p-2 rounded-full transition-colors w-full text-center ",children:e(o,{"aria-hidden":"true",size:24})})})}function D({visible:l}){let r="";return l&&(r="mobile"===l?"lg:hidden":"hidden lg:block"),e("div",{className:`h-6 w-px bg-gray-900/10 dark:bg-slate-900/0.1 ${r}`,"aria-hidden":"true"})}function I({title:r,icon:i,onClick:t}){return l("button",{type:"button",className:"-m-2.5 p-2.5 text-gray-400 dark:text-slate-50 hover:text-gray-500",onClick:t,children:[e("span",{className:"sr-only",children:r}),e(i,{className:"size-6","aria-hidden":"true",title:r})]})}function M({children:l,onClick:r}){return e(p,{onClick:r,children:l})}function E({href:l,onClick:r,children:i}){return e("a",{className:"dark:text-slate-50",href:l,onClick:r,children:i})}function W({children:r,logo:t,className:n}){return l("div",{className:i(n||"bg-indigo-600 dark:bg-indigo-950","flex flex-col h-full"),children:[t&&e("div",{className:"-mx-2 flex h-auto my-4 shrink-0 self-start",children:t}),e("div",{className:"flex-1 min-h-0 overflow-hidden px-2",children:e("nav",{className:"h-full flex flex-col",children:e("ul",{role:"list",className:"flex flex-col gap-y-2 overflow-y-auto h-full",children:r})})})]})}function j({children:i,title:t,action:n,isFooter:a=!1}){const{isOpen:s}=S();let o=s?l(r,{children:[t||"",n]}):e(d,{className:"size-6"});return l("li",{className:a?"mt-auto":"",children:[t&&e("div",{className:"text-xs font-medium h-8 flex items-center gap-x-2 px-2 text-sidebar-foreground/70",children:o}),e("ul",{"data-sidebar":"menu",className:"flex w-full min-w-0 flex-col gap-1",children:i})]})}function L({children:i,text:t}){const{isOpen:n}=S();return n?e(r,{children:i}):e(v,{children:l(N,{children:[e(b,{asChild:!0,children:i}),e(w,{side:"right",children:t})]})})}function P({external:r,className:t,tools:n,children:a,icon:s,href:o,current:c,onClick:d}){const{toggleMobile:h}=S();return e("li",{children:e(y,{onClick:()=>{setTimeout((()=>{h(!1)}),100)},children:e(L,{text:a,children:l("a",{href:o,onClick:e=>{r?(window.open(o,"_blank"),e.preventDefault(),e.stopPropagation()):d&&d(e)},className:i(c?"bg-sidebar-accent text-sidebar-accent-foreground":"text-sidebar-foreground hover:text-sidebar-accent-foreground hover:bg-sidebar-accent","group flex gap-x-3 rounded-md px-2 py-1.5 text-sm items-center h-8",t),children:[s&&e(s,{className:i(c?"bg-sidebar-accent text-sidebar-accent-foreground":"text-sidebar-foreground hover:text-sidebar-accent-foreground hover:bg-sidebar-accent","size-4 shrink-0"),"aria-hidden":"true"}),a,n&&e("div",{className:"flex items-center ml-auto",children:n})]})})})})}function R({sidebarClassName:o,className:c,title:d,children:m,logo:u,navbar:p,sidebar:v,mainNav:N}){null===localStorage.getItem("desktopSidebarOpen")&&localStorage.setItem("desktopSidebarOpen","true");const[b,w]=f(!1),[y,k]=f("true"===localStorage.getItem("desktopSidebarOpen")),[S,z]=f(window.innerWidth>=1024);x((()=>{const e=()=>{z(window.innerWidth>=1024)};return window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)}),[]);const F={isOpen:S?y:b,toggleDesktop:e=>{k(void 0===e?!y:e),localStorage.setItem("desktopSidebarOpen",JSON.stringify(!y))},toggleMobile:e=>{w(void 0===e?!b:e)}};return e(r,{children:e("div",{className:"flex flex-col h-screen overflow-y-hidden",children:l(C.Provider,{value:F,children:[e("div",{className:"w-full",children:N}),l("div",{className:"flex h-full overflow-y-auto w-full",children:[e(t,{show:b,as:g,children:l(n,{as:"div",className:"relative z-50 lg:hidden",onClose:w,children:[e(a,{as:g,enter:"transition-opacity ease-linear duration-300",enterFrom:"opacity-0",enterTo:"opacity-100",leave:"transition-opacity ease-linear duration-300",leaveFrom:"opacity-100",leaveTo:"opacity-0",children:e("div",{className:"fixed inset-0 bg-gray-900/80"})}),e("div",{className:"fixed inset-0 flex",children:e(a,{as:g,enter:"transition ease-in-out duration-300 transform",enterFrom:"-translate-x-full",enterTo:"translate-x-0",leave:"transition ease-in-out duration-300 transform",leaveFrom:"translate-x-0",leaveTo:"-translate-x-full",children:l(s,{className:"relative flex w-full max-w-xs flex-1",children:[e(W,{logo:u,className:o,children:v}),e("div",{className:"flex w-16 justify-center pt-5 items-start",children:l("button",{type:"button",className:"-m-2.5 p-2.5",onClick:()=>w(!1),children:[e("span",{className:"sr-only",children:"Close sidebar"}),e(h,{className:"size-6 text-white","aria-hidden":"true"})]})})]})})})]})}),e("div",{className:"hidden lg:block relative transition-all duration-300 "+(y?"w-72":"w-12"),children:e(W,{logo:u,className:o,children:v})}),l("div",{className:"w-full h-full overflow-y-hidden",children:[p?e(O,{title:d,logo:u,children:p}):null,e("main",{className:i("flex-1 h-full w-full relative flex flex-col",c),children:m})]})]})]})})})}export{R as AppLayout,k as FullHeightLayout,T as HamburgerButton,O as Navbar,M as NavbarButton,I as NavbarIconButton,E as NavbarLink,D as NavbarSeparator,W as Sidebar,C as SidebarContext,P as SidebarItem,j as SidebarSection,L as SidebarTooltip,z as TitleBar,S as useSidebarToggle};
|
|
2
2
|
//# sourceMappingURL=vertesia-ui-layout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertesia-ui-layout.js","sources":["esm/layout/FullHeightLayout.js","esm/layout/SidebarContext.js","esm/layout/TitleBar.js","esm/layout/Navbar.js","esm/layout/Sidebar.js","esm/layout/AppLayout.js"],"sourcesContent":["import { jsx as _jsx } from \"react/jsx-runtime\";\nimport clsx from 'clsx';\nexport function FullHeightLayout({ className, children }) {\n return (_jsx(\"div\", { className: clsx(\"flex flex-col\", \"h-full\", \"overflow-y-auto\", \n // \"dark:bg-slate-900 text-slate-950 dark:text-slate-200\",\n className), children: children }));\n}\nFullHeightLayout.Fixed = function Fixed({ heightClass, className, children }) {\n return (_jsx(\"div\", { className: clsx(\"w-full\", heightClass, className), children: children }));\n};\nFullHeightLayout.Body = function Body({ className, children }) {\n return (_jsx(\"div\", { className: clsx(\"grow overflow-auto\", \"min-h-0\", \"px-4 py-2\", className), children: children }));\n};\nFullHeightLayout.VR = function VDivider({}) {\n return (_jsx(\"div\", { className: \"w-[1px] border border-red-200\" }));\n};\nFullHeightLayout.HR = function HDivider({}) {\n return (_jsx(\"div\", { className: \"w-full h-1 border-b border-red-200\" }));\n};\n//# sourceMappingURL=FullHeightLayout.js.map","import { createContext, useContext } from \"react\";\nexport const SidebarContext = createContext({\n isOpen: false,\n toggleMobile: () => void 0,\n toggleDesktop: () => void 0,\n});\nexport function useSidebarToggle() {\n return useContext(SidebarContext);\n}\n//# sourceMappingURL=SidebarContext.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nexport function TitleBar({ title }) {\n return _jsx(\"div\", { className: 'self-center text-lg font-semibold', children: title });\n}\n//# sourceMappingURL=TitleBar.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport { Menu, Search } from 'lucide-react';\nimport { Button } from '@vertesia/ui/core';\nimport { useSidebarToggle } from './SidebarContext.js';\nimport { TitleBar } from './TitleBar.js';\nexport function Navbar({ children, logo, onSearch, title }) {\n return (_jsxs(\"div\", { className: \"sticky top-0 z-40 flex h-16 shrink-0 items-center gap-x-4 border-b px-4 shadow-2xs sm:gap-x-6 sm:px-6 lg:px-8\", children: [_jsx(HamburgerButton, {}), _jsx(\"div\", { className: \"lg:hidden\", children: logo }), onSearch && _jsx(NavbarSeparator, { visible: 'mobile' }), _jsxs(\"div\", { className: \"flex flex-1 gap-x-4 self-stretch lg:gap-x-6\", children: [_jsx(TitleBar, { title: title }), onSearch && _jsx(SearchBox, { onSearch: onSearch }), _jsx(\"div\", { className: \"flex items-center gap-x-4 lg:gap-x-6 ml-auto\", children: children })] })] }));\n}\nfunction SearchBox({}) {\n return (_jsxs(\"form\", { className: \"relative flex flex-1\", action: \"#\", method: \"GET\", children: [_jsx(\"label\", { htmlFor: \"search-field\", className: \"sr-only\", children: \"Search\" }), _jsx(Search, { className: \"pointer-events-none absolute inset-y-0 left-0 h-full w-5 text-gray-400\", \"aria-hidden\": \"true\" }), _jsx(\"input\", { id: \"search-field\", className: \"block h-full w-full border-0 py-0 pl-8 pr-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm\", placeholder: \"Search...\", type: \"search\", name: \"search\" })] }));\n}\nexport function HamburgerButton() {\n const { toggleDesktop, toggleMobile } = useSidebarToggle();\n const toggle = () => {\n if (window.innerWidth < 1024) {\n toggleMobile();\n }\n else {\n toggleDesktop();\n }\n };\n return (_jsx(_Fragment, { children: _jsx(Button, { variant: 'ghost', size: 'icon', onClick: () => toggle(), className: \"p-2 rounded-full transition-colors w-full text-center \", children: _jsx(Menu, { \"aria-hidden\": \"true\", size: 24 }) }) }));\n}\nexport function NavbarSeparator({ visible }) {\n let visibility = \"\";\n if (visible) {\n visibility = visible === \"mobile\" ? \"lg:hidden\" : \"hidden lg:block\";\n }\n return (_jsx(\"div\", { className: `h-6 w-px bg-gray-900/10 dark:bg-slate-900/0.1 ${visibility}`, \"aria-hidden\": \"true\" }));\n}\nexport function NavbarIconButton({ title, icon: Icon, onClick }) {\n return (_jsxs(\"button\", { type: \"button\", className: \"-m-2.5 p-2.5 text-gray-400 dark:text-slate-50 hover:text-gray-500\", onClick: onClick, children: [_jsx(\"span\", { className: \"sr-only\", children: title }), _jsx(Icon, { className: \"size-6\", \"aria-hidden\": \"true\", title: title })] }));\n}\nexport function NavbarButton({ children, onClick }) {\n return (_jsx(Button, { onClick: onClick, children: children }));\n}\nexport function NavbarLink({ href, onClick, children }) {\n return (_jsx(\"a\", { className: \"dark:text-slate-50\", href: href, onClick: onClick, children: children }));\n}\n//# sourceMappingURL=Navbar.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport clsx from 'clsx';\nimport { useSidebarToggle } from './SidebarContext';\nimport { Dot } from 'lucide-react';\nimport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@vertesia/ui/core';\nimport { Nav } from \"@vertesia/ui/router\";\nexport function Sidebar({ children, logo, className }) {\n return (_jsxs(\"div\", { className: clsx(className || \"bg-indigo-600 dark:bg-indigo-950\", \"flex flex-col h-full\"), children: [logo &&\n _jsx(\"div\", { className: \"-mx-2 flex h-auto my-4 shrink-0 self-start\", children: logo }), _jsx(\"div\", { className: \"flex-1 min-h-0 overflow-hidden px-2\", children: _jsx(\"nav\", { className: \"h-full flex flex-col\", children: _jsx(\"ul\", { role: \"list\", className: \"flex flex-col gap-y-2 overflow-y-auto h-full\", children: children }) }) })] }));\n}\nexport function SidebarSection({ children, title, action, isFooter = false }) {\n const { isOpen } = useSidebarToggle();\n let header = isOpen ? _jsxs(_Fragment, { children: [title || \"\", action] }) : _jsx(Dot, { className: 'size-6' });\n return (_jsxs(\"li\", { className: isFooter ? 'mt-auto' : '', children: [title && _jsx(\"div\", { className: \"text-xs font-medium h-8 flex items-center gap-x-2 px-2 text-sidebar-foreground/70\", children: header }), _jsx(\"ul\", { \"data-sidebar\": \"menu\", className: \"flex w-full min-w-0 flex-col gap-1\", children: children })] }));\n}\nexport function SidebarTooltip({ children, text }) {\n const { isOpen } = useSidebarToggle();\n return (isOpen ? _jsx(_Fragment, { children: children }) :\n _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: children }), _jsx(TooltipContent, { side: 'right', children: text })] }) }));\n}\nexport function SidebarItem({ external, className, tools, children, icon: Icon, href, current, onClick }) {\n const { toggleMobile } = useSidebarToggle();\n const _closeSideBar = () => {\n setTimeout(() => {\n toggleMobile(false);\n }, 100);\n };\n const onClickWrapper = (event) => {\n if (external) {\n window.open(href, '_blank');\n event.preventDefault(); // Prevent default link behavior\n event.stopPropagation(); // Stop the event from propagating\n }\n else if (onClick) {\n onClick(event);\n }\n };\n return (_jsx(\"li\", { children: _jsx(Nav, { onClick: _closeSideBar, children: _jsx(SidebarTooltip, { text: children, children: _jsxs(\"a\", { href: href, onClick: onClickWrapper, className: clsx(current\n ? 'bg-sidebar-accent text-sidebar-accent-foreground'\n : 'text-sidebar-foreground hover:text-sidebar-accent-foreground hover:bg-sidebar-accent', 'group flex gap-x-3 rounded-md px-2 py-1.5 text-sm items-center h-8', className), children: [Icon &&\n _jsx(Icon, { className: clsx(current\n ? 'bg-sidebar-accent text-sidebar-accent-foreground'\n : 'text-sidebar-foreground hover:text-sidebar-accent-foreground hover:bg-sidebar-accent', 'size-4 shrink-0'), \"aria-hidden\": \"true\" }), children, tools && _jsx(\"div\", { className: 'flex items-center ml-auto', children: tools })] }) }) }) }));\n}\n//# sourceMappingURL=Sidebar.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react';\nimport { X } from 'lucide-react';\nimport clsx from 'clsx';\nimport { Fragment, useEffect, useState } from 'react';\n// import { FullHeightLayout } from './FullHeightLayout.js'\nimport { Navbar } from './Navbar.js';\nimport { Sidebar } from './Sidebar.js';\nimport { SidebarContext } from './SidebarContext.js';\nexport function AppLayout({ sidebarClassName, className, title, children, logo, navbar, sidebar, mainNav }) {\n if (localStorage.getItem('desktopSidebarOpen') === null) {\n localStorage.setItem('desktopSidebarOpen', 'true');\n }\n const [sidebarOpen, setSidebarOpen] = useState(false);\n const [desktopSidebarOpen, setDesktopSidebarOpen] = useState(localStorage.getItem('desktopSidebarOpen') === 'true');\n const [isLargeScreen, setIsLargeScreen] = useState(window.innerWidth >= 1024);\n useEffect(() => {\n const handleResize = () => {\n setIsLargeScreen(window.innerWidth >= 1024);\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n const sidebarContextValue = {\n isOpen: isLargeScreen ? desktopSidebarOpen : sidebarOpen,\n toggleDesktop: (value) => {\n if (value === undefined) {\n setDesktopSidebarOpen(!desktopSidebarOpen);\n }\n else {\n setDesktopSidebarOpen(value);\n }\n localStorage.setItem('desktopSidebarOpen', JSON.stringify(!desktopSidebarOpen));\n },\n toggleMobile: (value) => {\n if (value === undefined) {\n setSidebarOpen(!sidebarOpen);\n }\n else {\n setSidebarOpen(value);\n }\n },\n };\n return (_jsx(_Fragment, { children: _jsx(\"div\", { className: 'flex flex-col h-screen overflow-y-hidden', children: _jsxs(SidebarContext.Provider, { value: sidebarContextValue, children: [_jsx(\"div\", { className: 'w-full', children: mainNav }), _jsxs(\"div\", { className: 'flex h-full overflow-y-auto w-full', children: [_jsx(Transition, { show: sidebarOpen, as: Fragment, children: _jsxs(Dialog, { as: \"div\", className: \"relative z-50 lg:hidden\", onClose: setSidebarOpen, children: [_jsx(TransitionChild, { as: Fragment, enter: \"transition-opacity ease-linear duration-300\", enterFrom: \"opacity-0\", enterTo: \"opacity-100\", leave: \"transition-opacity ease-linear duration-300\", leaveFrom: \"opacity-100\", leaveTo: \"opacity-0\", children: _jsx(\"div\", { className: \"fixed inset-0 bg-gray-900/80\" }) }), _jsx(\"div\", { className: \"fixed inset-0 flex\", children: _jsx(TransitionChild, { as: Fragment, enter: \"transition ease-in-out duration-300 transform\", enterFrom: \"-translate-x-full\", enterTo: \"translate-x-0\", leave: \"transition ease-in-out duration-300 transform\", leaveFrom: \"translate-x-0\", leaveTo: \"-translate-x-full\", children: _jsxs(DialogPanel, { className: \"relative flex w-full max-w-xs flex-1\", children: [_jsx(Sidebar, { logo: logo, className: sidebarClassName, children: sidebar }), _jsx(\"div\", { className: \"flex w-16 justify-center pt-5 items-start\", children: _jsxs(\"button\", { type: \"button\", className: \"-m-2.5 p-2.5\", onClick: () => setSidebarOpen(false), children: [_jsx(\"span\", { className: \"sr-only\", children: \"Close sidebar\" }), _jsx(X, { className: \"size-6 text-white\", \"aria-hidden\": \"true\" })] }) })] }) }) })] }) }), _jsx(\"div\", { className: `hidden lg:block relative transition-all duration-300 ${desktopSidebarOpen ? 'w-72' : 'w-12'}`, children: _jsx(Sidebar, { logo: logo, className: sidebarClassName, children: sidebar }) }), _jsxs(\"div\", { className: \"w-full h-full overflow-y-hidden\", children: [navbar ? (_jsx(Navbar, { title: title, logo: logo, children: navbar })) : null, _jsx(\"main\", { className: clsx(\"flex-1 h-full w-full relative flex flex-col\", className), children: children })] })] })] }) }) }));\n}\n//# sourceMappingURL=AppLayout.js.map"],"names":["FullHeightLayout","className","children","_jsx","clsx","Fixed","heightClass","Body","VR","HR","SidebarContext","createContext","isOpen","toggleMobile","toggleDesktop","useSidebarToggle","useContext","TitleBar","title","Navbar","logo","onSearch","_jsxs","HamburgerButton","NavbarSeparator","visible","SearchBox","action","method","htmlFor","Search","id","placeholder","type","name","_Fragment","Button","variant","size","onClick","window","innerWidth","Menu","visibility","NavbarIconButton","icon","Icon","NavbarButton","NavbarLink","href","Sidebar","role","SidebarSection","isFooter","header","Dot","SidebarTooltip","text","TooltipProvider","Tooltip","TooltipTrigger","asChild","TooltipContent","side","SidebarItem","external","tools","current","Nav","setTimeout","event","open","preventDefault","stopPropagation","AppLayout","sidebarClassName","navbar","sidebar","mainNav","localStorage","getItem","setItem","sidebarOpen","setSidebarOpen","useState","desktopSidebarOpen","setDesktopSidebarOpen","isLargeScreen","setIsLargeScreen","useEffect","handleResize","addEventListener","removeEventListener","sidebarContextValue","value","undefined","JSON","stringify","Provider","Transition","show","as","Fragment","Dialog","onClose","TransitionChild","enter","enterFrom","enterTo","leave","leaveFrom","leaveTo","DialogPanel","X"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vertesia-ui-layout.js","sources":["esm/layout/FullHeightLayout.js","esm/layout/SidebarContext.js","esm/layout/TitleBar.js","esm/layout/Navbar.js","esm/layout/Sidebar.js","esm/layout/AppLayout.js"],"sourcesContent":["import { jsx as _jsx } from \"react/jsx-runtime\";\nimport clsx from 'clsx';\nexport function FullHeightLayout({ className, children }) {\n return (_jsx(\"div\", { className: clsx(\"flex flex-col\", \"h-full\", \"overflow-y-auto\", \"px-2\", className), children: children }));\n}\nFullHeightLayout.Fixed = function Fixed({ heightClass, className, children }) {\n return (_jsx(\"div\", { className: clsx(\"w-full\", heightClass, className), children: children }));\n};\nFullHeightLayout.Body = function Body({ className, children }) {\n return (_jsx(\"div\", { className: clsx(\"grow overflow-auto\", \"min-h-0\", \"p-2\", className), children: children }));\n};\nFullHeightLayout.VR = function VDivider({}) {\n return (_jsx(\"div\", { className: \"w-[1px] border border-red-200\" }));\n};\nFullHeightLayout.HR = function HDivider({}) {\n return (_jsx(\"div\", { className: \"w-full h-1 border-b border-red-200\" }));\n};\n//# sourceMappingURL=FullHeightLayout.js.map","import { createContext, useContext } from \"react\";\nexport const SidebarContext = createContext({\n isOpen: false,\n toggleMobile: () => void 0,\n toggleDesktop: () => void 0,\n});\nexport function useSidebarToggle() {\n return useContext(SidebarContext);\n}\n//# sourceMappingURL=SidebarContext.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nexport function TitleBar({ title }) {\n return _jsx(\"div\", { className: 'self-center text-lg font-semibold', children: title });\n}\n//# sourceMappingURL=TitleBar.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport { Menu, Search } from 'lucide-react';\nimport { Button } from '@vertesia/ui/core';\nimport { useSidebarToggle } from './SidebarContext.js';\nimport { TitleBar } from './TitleBar.js';\nexport function Navbar({ children, logo, onSearch, title }) {\n return (_jsxs(\"div\", { className: \"sticky top-0 z-40 flex h-16 shrink-0 items-center gap-x-4 border-b px-4 shadow-2xs sm:gap-x-6 sm:px-6 lg:px-8\", children: [_jsx(HamburgerButton, {}), _jsx(\"div\", { className: \"lg:hidden\", children: logo }), onSearch && _jsx(NavbarSeparator, { visible: 'mobile' }), _jsxs(\"div\", { className: \"flex flex-1 gap-x-4 self-stretch lg:gap-x-6\", children: [_jsx(TitleBar, { title: title }), onSearch && _jsx(SearchBox, { onSearch: onSearch }), _jsx(\"div\", { className: \"flex items-center gap-x-4 lg:gap-x-6 ml-auto\", children: children })] })] }));\n}\nfunction SearchBox({}) {\n return (_jsxs(\"form\", { className: \"relative flex flex-1\", action: \"#\", method: \"GET\", children: [_jsx(\"label\", { htmlFor: \"search-field\", className: \"sr-only\", children: \"Search\" }), _jsx(Search, { className: \"pointer-events-none absolute inset-y-0 left-0 h-full w-5 text-gray-400\", \"aria-hidden\": \"true\" }), _jsx(\"input\", { id: \"search-field\", className: \"block h-full w-full border-0 py-0 pl-8 pr-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm\", placeholder: \"Search...\", type: \"search\", name: \"search\" })] }));\n}\nexport function HamburgerButton() {\n const { toggleDesktop, toggleMobile } = useSidebarToggle();\n const toggle = () => {\n if (window.innerWidth < 1024) {\n toggleMobile();\n }\n else {\n toggleDesktop();\n }\n };\n return (_jsx(_Fragment, { children: _jsx(Button, { variant: 'ghost', size: 'icon', onClick: () => toggle(), className: \"p-2 rounded-full transition-colors w-full text-center \", children: _jsx(Menu, { \"aria-hidden\": \"true\", size: 24 }) }) }));\n}\nexport function NavbarSeparator({ visible }) {\n let visibility = \"\";\n if (visible) {\n visibility = visible === \"mobile\" ? \"lg:hidden\" : \"hidden lg:block\";\n }\n return (_jsx(\"div\", { className: `h-6 w-px bg-gray-900/10 dark:bg-slate-900/0.1 ${visibility}`, \"aria-hidden\": \"true\" }));\n}\nexport function NavbarIconButton({ title, icon: Icon, onClick }) {\n return (_jsxs(\"button\", { type: \"button\", className: \"-m-2.5 p-2.5 text-gray-400 dark:text-slate-50 hover:text-gray-500\", onClick: onClick, children: [_jsx(\"span\", { className: \"sr-only\", children: title }), _jsx(Icon, { className: \"size-6\", \"aria-hidden\": \"true\", title: title })] }));\n}\nexport function NavbarButton({ children, onClick }) {\n return (_jsx(Button, { onClick: onClick, children: children }));\n}\nexport function NavbarLink({ href, onClick, children }) {\n return (_jsx(\"a\", { className: \"dark:text-slate-50\", href: href, onClick: onClick, children: children }));\n}\n//# sourceMappingURL=Navbar.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport clsx from 'clsx';\nimport { useSidebarToggle } from './SidebarContext';\nimport { Dot } from 'lucide-react';\nimport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@vertesia/ui/core';\nimport { Nav } from \"@vertesia/ui/router\";\nexport function Sidebar({ children, logo, className }) {\n return (_jsxs(\"div\", { className: clsx(className || \"bg-indigo-600 dark:bg-indigo-950\", \"flex flex-col h-full\"), children: [logo &&\n _jsx(\"div\", { className: \"-mx-2 flex h-auto my-4 shrink-0 self-start\", children: logo }), _jsx(\"div\", { className: \"flex-1 min-h-0 overflow-hidden px-2\", children: _jsx(\"nav\", { className: \"h-full flex flex-col\", children: _jsx(\"ul\", { role: \"list\", className: \"flex flex-col gap-y-2 overflow-y-auto h-full\", children: children }) }) })] }));\n}\nexport function SidebarSection({ children, title, action, isFooter = false }) {\n const { isOpen } = useSidebarToggle();\n let header = isOpen ? _jsxs(_Fragment, { children: [title || \"\", action] }) : _jsx(Dot, { className: 'size-6' });\n return (_jsxs(\"li\", { className: isFooter ? 'mt-auto' : '', children: [title && _jsx(\"div\", { className: \"text-xs font-medium h-8 flex items-center gap-x-2 px-2 text-sidebar-foreground/70\", children: header }), _jsx(\"ul\", { \"data-sidebar\": \"menu\", className: \"flex w-full min-w-0 flex-col gap-1\", children: children })] }));\n}\nexport function SidebarTooltip({ children, text }) {\n const { isOpen } = useSidebarToggle();\n return (isOpen ? _jsx(_Fragment, { children: children }) :\n _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: children }), _jsx(TooltipContent, { side: 'right', children: text })] }) }));\n}\nexport function SidebarItem({ external, className, tools, children, icon: Icon, href, current, onClick }) {\n const { toggleMobile } = useSidebarToggle();\n const _closeSideBar = () => {\n setTimeout(() => {\n toggleMobile(false);\n }, 100);\n };\n const onClickWrapper = (event) => {\n if (external) {\n window.open(href, '_blank');\n event.preventDefault(); // Prevent default link behavior\n event.stopPropagation(); // Stop the event from propagating\n }\n else if (onClick) {\n onClick(event);\n }\n };\n return (_jsx(\"li\", { children: _jsx(Nav, { onClick: _closeSideBar, children: _jsx(SidebarTooltip, { text: children, children: _jsxs(\"a\", { href: href, onClick: onClickWrapper, className: clsx(current\n ? 'bg-sidebar-accent text-sidebar-accent-foreground'\n : 'text-sidebar-foreground hover:text-sidebar-accent-foreground hover:bg-sidebar-accent', 'group flex gap-x-3 rounded-md px-2 py-1.5 text-sm items-center h-8', className), children: [Icon &&\n _jsx(Icon, { className: clsx(current\n ? 'bg-sidebar-accent text-sidebar-accent-foreground'\n : 'text-sidebar-foreground hover:text-sidebar-accent-foreground hover:bg-sidebar-accent', 'size-4 shrink-0'), \"aria-hidden\": \"true\" }), children, tools && _jsx(\"div\", { className: 'flex items-center ml-auto', children: tools })] }) }) }) }));\n}\n//# sourceMappingURL=Sidebar.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react';\nimport { X } from 'lucide-react';\nimport clsx from 'clsx';\nimport { Fragment, useEffect, useState } from 'react';\n// import { FullHeightLayout } from './FullHeightLayout.js'\nimport { Navbar } from './Navbar.js';\nimport { Sidebar } from './Sidebar.js';\nimport { SidebarContext } from './SidebarContext.js';\nexport function AppLayout({ sidebarClassName, className, title, children, logo, navbar, sidebar, mainNav }) {\n if (localStorage.getItem('desktopSidebarOpen') === null) {\n localStorage.setItem('desktopSidebarOpen', 'true');\n }\n const [sidebarOpen, setSidebarOpen] = useState(false);\n const [desktopSidebarOpen, setDesktopSidebarOpen] = useState(localStorage.getItem('desktopSidebarOpen') === 'true');\n const [isLargeScreen, setIsLargeScreen] = useState(window.innerWidth >= 1024);\n useEffect(() => {\n const handleResize = () => {\n setIsLargeScreen(window.innerWidth >= 1024);\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n const sidebarContextValue = {\n isOpen: isLargeScreen ? desktopSidebarOpen : sidebarOpen,\n toggleDesktop: (value) => {\n if (value === undefined) {\n setDesktopSidebarOpen(!desktopSidebarOpen);\n }\n else {\n setDesktopSidebarOpen(value);\n }\n localStorage.setItem('desktopSidebarOpen', JSON.stringify(!desktopSidebarOpen));\n },\n toggleMobile: (value) => {\n if (value === undefined) {\n setSidebarOpen(!sidebarOpen);\n }\n else {\n setSidebarOpen(value);\n }\n },\n };\n return (_jsx(_Fragment, { children: _jsx(\"div\", { className: 'flex flex-col h-screen overflow-y-hidden', children: _jsxs(SidebarContext.Provider, { value: sidebarContextValue, children: [_jsx(\"div\", { className: 'w-full', children: mainNav }), _jsxs(\"div\", { className: 'flex h-full overflow-y-auto w-full', children: [_jsx(Transition, { show: sidebarOpen, as: Fragment, children: _jsxs(Dialog, { as: \"div\", className: \"relative z-50 lg:hidden\", onClose: setSidebarOpen, children: [_jsx(TransitionChild, { as: Fragment, enter: \"transition-opacity ease-linear duration-300\", enterFrom: \"opacity-0\", enterTo: \"opacity-100\", leave: \"transition-opacity ease-linear duration-300\", leaveFrom: \"opacity-100\", leaveTo: \"opacity-0\", children: _jsx(\"div\", { className: \"fixed inset-0 bg-gray-900/80\" }) }), _jsx(\"div\", { className: \"fixed inset-0 flex\", children: _jsx(TransitionChild, { as: Fragment, enter: \"transition ease-in-out duration-300 transform\", enterFrom: \"-translate-x-full\", enterTo: \"translate-x-0\", leave: \"transition ease-in-out duration-300 transform\", leaveFrom: \"translate-x-0\", leaveTo: \"-translate-x-full\", children: _jsxs(DialogPanel, { className: \"relative flex w-full max-w-xs flex-1\", children: [_jsx(Sidebar, { logo: logo, className: sidebarClassName, children: sidebar }), _jsx(\"div\", { className: \"flex w-16 justify-center pt-5 items-start\", children: _jsxs(\"button\", { type: \"button\", className: \"-m-2.5 p-2.5\", onClick: () => setSidebarOpen(false), children: [_jsx(\"span\", { className: \"sr-only\", children: \"Close sidebar\" }), _jsx(X, { className: \"size-6 text-white\", \"aria-hidden\": \"true\" })] }) })] }) }) })] }) }), _jsx(\"div\", { className: `hidden lg:block relative transition-all duration-300 ${desktopSidebarOpen ? 'w-72' : 'w-12'}`, children: _jsx(Sidebar, { logo: logo, className: sidebarClassName, children: sidebar }) }), _jsxs(\"div\", { className: \"w-full h-full overflow-y-hidden\", children: [navbar ? (_jsx(Navbar, { title: title, logo: logo, children: navbar })) : null, _jsx(\"main\", { className: clsx(\"flex-1 h-full w-full relative flex flex-col\", className), children: children })] })] })] }) }) }));\n}\n//# sourceMappingURL=AppLayout.js.map"],"names":["FullHeightLayout","className","children","_jsx","clsx","Fixed","heightClass","Body","VR","HR","SidebarContext","createContext","isOpen","toggleMobile","toggleDesktop","useSidebarToggle","useContext","TitleBar","title","Navbar","logo","onSearch","_jsxs","HamburgerButton","NavbarSeparator","visible","SearchBox","action","method","htmlFor","Search","id","placeholder","type","name","_Fragment","Button","variant","size","onClick","window","innerWidth","Menu","visibility","NavbarIconButton","icon","Icon","NavbarButton","NavbarLink","href","Sidebar","role","SidebarSection","isFooter","header","Dot","SidebarTooltip","text","TooltipProvider","Tooltip","TooltipTrigger","asChild","TooltipContent","side","SidebarItem","external","tools","current","Nav","setTimeout","event","open","preventDefault","stopPropagation","AppLayout","sidebarClassName","navbar","sidebar","mainNav","localStorage","getItem","setItem","sidebarOpen","setSidebarOpen","useState","desktopSidebarOpen","setDesktopSidebarOpen","isLargeScreen","setIsLargeScreen","useEffect","handleResize","addEventListener","removeEventListener","sidebarContextValue","value","undefined","JSON","stringify","Provider","Transition","show","as","Fragment","Dialog","onClose","TransitionChild","enter","enterFrom","enterTo","leave","leaveFrom","leaveTo","DialogPanel","X"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jwtDecode as e}from"jwt-decode";import{Env as t}from"@vertesia/ui/env";import{createContext as o,useContext as r,useCallback as n,useState as i,useEffect as s}from"react";import{VertesiaClient as a}from"@vertesia/client";import{getAnalytics as c,logEvent as l}from"firebase/analytics";import{initializeApp as u}from"firebase/app";import{getAuth as h,onAuthStateChanged as d}from"firebase/auth";import{jsx as g}from"react/jsx-runtime";let m=null,p=null,f=null;function w(){if(!m)try{m=u(t.firebase)}catch(e){throw console.error("Failed to initialize Firebase app:",e),new Error("Firebase initialization failed - environment may not be properly initialized")}return m}function v(){return p||(p=c(w())),p}function k(){return f||(f=h(w())),f}async function b(e){if(e)try{e&&console.log(`Resolving tenant ID from email: ${e}`);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:e}),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(e){console.error(`Failed to resolve tenant ID: HTTP ${o.status}`)}if(404===o.status)return void console.warn(`Tenant not found for ${e}`);throw new Error(`HTTP error ${o.status}`)}const r=await o.json();if(r&&r.firebaseTenantId){const e=k();return e.tenantId=r.firebaseTenantId,t.firebase.providerType=r.provider??"oidc",console.log(`Tenant ID set to ${e.tenantId}`),r}return void console.error(`Invalid response format, missing tenantId for ${e}`)}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("No tenant name or email specified, skipping tenant setup")}async function S(e){const o=k().currentUser;return o?o.getIdToken(e).then((r=>(t.logger.info("Got Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:e}}),r))).catch((r=>(t.logger.error("Failed to get Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:e,error:r}}),console.error("Failed to get access token",r),null))):(t.logger.warn("No user found"),Promise.resolve(null))}class y{types;map={};constructor(e){this.types=e,e.sort(((e,t)=>e.name.localeCompare(t.name)));for(const t of e)this.map[t.id]=t}getType(e){return this.map[e]}getTypeLayout(e){const t=this.map[e];return t?t.table_layout:void 0}getTypeName(e){const t=this.map[e];return t?t.name:void 0}}const T="composableai.lastSelectedAccountId",_="composableai.lastSelectedProjectId";class I{isLoading=!0;client;authError;authToken;typeRegistry;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(e,o){this.client=e||new a({serverUrl:t.endpoints.studio,storeUrl:t.endpoints.zeno}),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 U().then((t=>{const o=t?.rawToken;if(!o)throw new Error("No token available");return this.authToken=e(o),o}))}signOut(){this.logout()}getAccount(){return this.authToken?.account}async login(o){return this.authError=void 0,this.isLoading=!1,this.client.withAuthCallback((()=>this.authCallback)),this.authToken=e(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(T,this.authToken.account.id),localStorage.setItem(_+"-"+this.authToken.account.id,this.authToken.project?.id??""),t.onLogin?.(this.authToken),await Promise.all([this._loadTypes(),this.fetchOnboardingStatus()]),Promise.resolve()}isLoggedIn(){return!!this.authToken}logout(){console.log("Logging out"),this.authToken&&k().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.typeRegistry=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0)}async switchAccount(e){localStorage.setItem(T,e),this&&(this.account&&this.project?localStorage.setItem(_+"-"+this.account.id,this.project.id):this.account&&localStorage.removeItem(_+"-"+this.account.id)),window.location.replace("/?a="+e)}async switchProject(e){this.account&&localStorage.setItem(_+"-"+this.account.id,e),window.location.replace("/?a="+this.account?.id+"&p="+e)}async _loadTypes(){if(this.project)return this.store.types.list({},{layout:!0}).then((e=>this.typeRegistry=new y(e))).catch((e=>{throw console.error("Failed to fetch object types",e),e}));console.log("No project selected")}async reloadTypes(){return this._loadTypes().then((()=>{this.setSession?.(this.clone())}))}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 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 I(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.typeRegistry=this.typeRegistry,e.onboardingComplete=this.onboardingComplete,e}}const j=o(void 0);function F(){const e=r(j);if(!e)throw new Error("useUserSession must be used within a UserSessionProvider");return e}let A,E;async function P(o,r,n,i){console.log(`Getting/refreshing composable token for account ${r} and project ${n} `),t.logger.info("Getting/refreshing composable token",{vertesia:{account_id:r,project_id:n}});const s=await o();if(!s)throw console.log("No id token found - using cookie auth"),new Error("No id token found");console.log("Fetching composable token from "+t.endpoints.studio),t.logger.info("Fetching composable token from"+t.endpoints.studio,{vertesia:{account_id:r,project_id:n}});const a=new URL(t.endpoints.studio+"/auth/token");r&&a.searchParams.set("accountId",r),n&&a.searchParams.set("projectId",n),i&&a.searchParams.set("ttl",String(i)),console.log(`Getting composable token for account ${r} and project ${n}`),t.logger.info("Getting composable token",{vertesia:{account_id:r,project_id:n}});const c=await fetch(a,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`}}).catch((e=>{throw localStorage.removeItem(T),localStorage.removeItem(_),console.error("Failed to get composable token",e),t.logger.error("Failed to get composable token",{vertesia:{account_id:r,project_id:n,error:e}}),new Error("Failed to get composable token")}));if(s&&412===c?.status){console.log("412: auth succeeded but user doesn't exist - signup required",c?.status),t.logger.error("412: auth succeeded but user doesn't exist - signup required",{vertesia:{account_id:r,project_id:n,status:c?.status}});const o=e(s);if(!o?.email)throw t.logger.error("No email found in id token"),new Error("No email found in id token");throw t.logger.error("User not found",{vertesia:{account_id:r,project_id:n,email:o.email}}),new C("User not found",o.email)}if(!c||!c.ok)throw console.error("Failed to get composable token",c),t.logger.error("Failed to get composable token",{vertesia:{account_id:r,project_id:n,status:c?.status}}),new Error("Failed to get composable token");const{token:l}=await c.json().catch((e=>{t.logger.error("Failed to parse composable token",{vertesia:{account_id:r,project_id:n,error:e}}),console.error("Failed to parse composable token",e)}));return l}async function $(e,t,o){return P(S,e,t,o)}async function U(o,r,n,i=!1){const s=o??localStorage.getItem(T)??void 0,a=r??localStorage.getItem(_+"-"+s)??void 0;if(!i&&A&&E&&E.exp>Date.now()/1e3+300)return{rawToken:A,token:E,error:!1};if(k().currentUser?A=await $(s,a):(n||A)&&(A=await P((()=>Promise.resolve(n??A)),s,a)),!A)throw t.logger.error("Cannot acquire a composable token",{vertesia:{account_id:s,project_id:a}}),new Error("Cannot acquire a composable token");if(E=e(A),!E||!E.exp||!A)throw console.error("Invalid composable token",E),t.logger.error("Invalid composable token",{vertesia:{account_id:s,project_id:a}}),new Error("Invalid composable token");return{rawToken:A,token:E,error:!1}}class C extends Error{email;constructor(e,t){super(e),this.name="UserNotFoundError",this.email=t}}const N="auth_state",L="auth_state_expiry";const R=[".composable.sh",".vertesia.dev","vertesia.app"];function D({children:e}){const o=new URLSearchParams(location.hash.substring(1)),r=o.get("token"),a=o.get("state"),[c,l]=i(new I),{generateState:u,verifyState:h}={generateState:n((()=>{const e=crypto.randomUUID(),t=Date.now()+3e5;return sessionStorage.setItem(N,e),sessionStorage.setItem(L,t.toString()),e}),[]),verifyState:n((e=>{if(!e)return"Missing state";const t=sessionStorage.getItem(N),o=parseInt(sessionStorage.getItem(L)||"0");let r;return r=t!==e?`State mismatched (${t} !== ${e})`:Date.now()>o?"State expired":void 0,sessionStorage.removeItem(N),sessionStorage.removeItem(L),r}),[]),clearState:n((()=>{sessionStorage.removeItem(N),sessionStorage.removeItem(L)}),[])},m=(e,t)=>{const o=new URL("https://internal-auth.vertesia.app/"),r=new URL(window.location.href);r.hash="",o.searchParams.set("redirect_uri",r.toString()),o.searchParams.set("state",u()),location.replace(o.toString())};return s((()=>{console.log("Auth: starting auth flow"),t.logger.info("Starting auth flow");const e=new URL(window.location.href),o=e.searchParams.get("a")??localStorage.getItem(T)??void 0,n=e.searchParams.get("p")??localStorage.getItem(_+"-"+o)??void 0;if(console.log("Auth: selected account",o),console.log("Auth: selected project",n),t.logger.info("Selected account and project",{vertesia:{account_id:o,project_id:n}}),r&&a){const e=h(a);return e&&(console.error(`Auth: invalid state: ${e}`),t.logger.error(`Invalid state: ${e}`,{vertesia:{state:a}}),m()),void U(o,n,r).then((e=>{c.login(e.rawToken).then((()=>{l(c.clone()),window.location.hash=""}))})).catch((e=>{console.error("Failed to fetch user token from studio, redirecting to central auth",e),t.logger.error("Failed to fetch user token from studio, redirecting to central auth",{vertesia:{error:e}}),m()}))}return c.isLoggedIn()||(console.log("Auth: not logged in & no token/state"),t.logger.info("Not logged in & no token/state",{vertesia:{account_id:o,project_id:n}}),t.isDocker||R.some((e=>window.location.hostname.endsWith(e)))?(console.log("Auth: on dev domain, redirecting to central auth with selection",o,n),t.logger.info("Redirecting to central auth with selection",{vertesia:{account_id:o,project_id:n}}),m()):(console.log("Auth: not on dev domain"),t.logger.info("Not on dev domain",{vertesia:{account_id:o,project_id:n}}))),d(k(),(async e=>{e?(console.log("Auth: successful login with firebase"),t.logger.info("Successful login with firebase",{vertesia:{account_id:o,project_id:n}}),c.setSession=l,await U(o,n).then((e=>{c.login(e.rawToken).then((()=>l(c.clone())))})).catch((e=>{console.error("Failed to fetch user token from studio",e),t.logger.error("Failed to fetch user token from studio",{vertesia:{account_id:o,project_id:n,error:e}}),e instanceof C||c.logout(),c.isLoading=!1,c.authError=e,l(c.clone())}))):(console.log("Auth: using anonymous user"),t.logger.info("Using anonymous user",{vertesia:{account_id:o,project_id:n}}),c.client.withAuthCallback(void 0),c.logout(),l(c.clone()))}))}),[]),g(j.Provider,{value:c,children:e})}function x(){return{tagUserSession:async e=>{const t=window.localStorage.getItem("composableSignupData");e?t&&window.localStorage.removeItem("composableSignupData"):console.error("No user found -- skipping tagging")},trackEvent:(e,o)=>{t.isProd||console.debug("track event",e,o),l(v(),e,{...o,debug_mode:!t.isProd})}}}export{T as LastSelectedAccountId_KEY,_ as LastSelectedProjectId_KEY,y as TypeRegistry,C as UserNotFoundError,I as UserSession,j as UserSessionContext,D as UserSessionProvider,P as fetchComposableToken,$ as fetchComposableTokenFromFirebaseToken,U as getComposableToken,v as getFirebaseAnalytics,w as getFirebaseApp,k as getFirebaseAuth,S as getFirebaseAuthToken,b as setFirebaseTenant,x as useUXTracking,F as useUserSession};
|
|
1
|
+
import{jwtDecode as e}from"jwt-decode";import{Env as t}from"@vertesia/ui/env";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{createContext as a,useContext as c,useCallback as l,useState as u,useEffect as h}from"react";import{VertesiaClient as d}from"@vertesia/client";import{jsx as g}from"react/jsx-runtime";const m="composableai.lastSelectedAccountId",p="composableai.lastSelectedProjectId";let f,w,v=null,k=null,b=null;function S(){if(!v)try{v=n(t.firebase)}catch(e){throw console.error("Failed to initialize Firebase app:",e),new Error("Firebase initialization failed - environment may not be properly initialized")}return v}function y(){return k||(k=o(S())),k}function T(){return b||(b=i(S())),b}async function _(e){if(e)try{e&&console.log(`Resolving tenant ID from email: ${e}`);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:e}),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(e){console.error(`Failed to resolve tenant ID: HTTP ${o.status}`)}if(404===o.status)return void console.warn(`Tenant not found for ${e}`);throw new Error(`HTTP error ${o.status}`)}const r=await o.json();if(r&&r.firebaseTenantId){const e=T();return e.tenantId=r.firebaseTenantId,t.firebase.providerType=r.provider??"oidc",console.log(`Tenant ID set to ${e.tenantId}`),r}return void console.error(`Invalid response format, missing tenantId for ${e}`)}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("No tenant name or email specified, skipping tenant setup")}async function I(e){const o=T().currentUser;return o?o.getIdToken(e).then((r=>(t.logger.info("Got Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:e}}),r))).catch((r=>(t.logger.error("Failed to get Firebase token",{vertesia:{user_email:o.email,user_name:o.displayName,user_id:o.uid,refresh:e,error:r}}),console.error("Failed to get access token",r),null))):(t.logger.warn("No user found"),Promise.resolve(null))}async function j(o,r,n,i){console.log(`Getting/refreshing composable token for account ${r} and project ${n} `),t.logger.info("Getting/refreshing composable token",{vertesia:{account_id:r,project_id:n}});const s=await o();if(!s)throw console.log("No id token found - using cookie auth"),new Error("No id token found");console.log("Fetching composable token from "+t.endpoints.studio),t.logger.info("Fetching composable token from"+t.endpoints.studio,{vertesia:{account_id:r,project_id:n}});const a=new URL(t.endpoints.studio+"/auth/token");r&&a.searchParams.set("accountId",r),n&&a.searchParams.set("projectId",n),i&&a.searchParams.set("ttl",String(i)),console.log(`Getting composable token for account ${r} and project ${n}`),t.logger.info("Getting composable token",{vertesia:{account_id:r,project_id:n}});const c=await fetch(a,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`}}).catch((e=>{throw localStorage.removeItem(m),localStorage.removeItem(p),console.error("Failed to get composable token",e),t.logger.error("Failed to get composable token",{vertesia:{account_id:r,project_id:n,error:e}}),new Error("Failed to get composable token")}));if(s&&412===c?.status){console.log("412: auth succeeded but user doesn't exist - signup required",c?.status),t.logger.error("412: auth succeeded but user doesn't exist - signup required",{vertesia:{account_id:r,project_id:n,status:c?.status}});const o=e(s);if(!o?.email)throw t.logger.error("No email found in id token"),new Error("No email found in id token");throw t.logger.error("User not found",{vertesia:{account_id:r,project_id:n,email:o.email}}),new E("User not found",o.email)}if(!c||!c.ok)throw console.error("Failed to get composable token",c),t.logger.error("Failed to get composable token",{vertesia:{account_id:r,project_id:n,status:c?.status}}),new Error("Failed to get composable token");const{token:l}=await c.json().catch((e=>{t.logger.error("Failed to parse composable token",{vertesia:{account_id:r,project_id:n,error:e}}),console.error("Failed to parse composable token",e)}));return l}async function F(e,t,o){return j(I,e,t,o)}async function A(o,r,n,i=!1){const s=o??localStorage.getItem(m)??void 0,a=r??localStorage.getItem(p+"-"+s)??void 0;if(!i&&f&&w&&w.exp>Date.now()/1e3+300)return{rawToken:f,token:w,error:!1};if(T().currentUser?f=await F(s,a):(n||f)&&(f=await j((()=>Promise.resolve(n??f)),s,a)),!f)throw t.logger.error("Cannot acquire a composable token",{vertesia:{account_id:s,project_id:a}}),new Error("Cannot acquire a composable token");if(w=e(f),!w||!w.exp||!f)throw console.error("Invalid composable token",w),t.logger.error("Invalid composable token",{vertesia:{account_id:s,project_id:a}}),new Error("Invalid composable token");return{rawToken:f,token:w,error:!1}}class E extends Error{email;constructor(e,t){super(e),this.name="UserNotFoundError",this.email=t}}class P{types;map={};constructor(e){this.types=e,e.sort(((e,t)=>e.name.localeCompare(t.name)));for(const t of e)this.map[t.id]=t}getType(e){return this.map[e]}getTypeLayout(e){const t=this.map[e];return t?t.table_layout:void 0}getTypeName(e){const t=this.map[e];return t?t.name:void 0}}class ${isLoading=!0;client;authError;authToken;typeRegistry;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(e,o){this.client=e||new d({serverUrl:t.endpoints.studio,storeUrl:t.endpoints.zeno}),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 A().then((t=>{const o=t?.rawToken;if(!o)throw new Error("No token available");return this.authToken=e(o),o}))}signOut(){this.logout()}getAccount(){return this.authToken?.account}async login(o){return this.authError=void 0,this.isLoading=!1,this.client.withAuthCallback((()=>this.authCallback)),this.authToken=e(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(m,this.authToken.account.id),localStorage.setItem(p+"-"+this.authToken.account.id,this.authToken.project?.id??""),t.onLogin?.(this.authToken),await Promise.all([this._loadTypes(),this.fetchOnboardingStatus()]),Promise.resolve()}isLoggedIn(){return!!this.authToken}logout(){console.log("Logging out"),this.authToken&&T().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.typeRegistry=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0)}async switchAccount(e){localStorage.setItem(m,e),this&&(this.account&&this.project?localStorage.setItem(p+"-"+this.account.id,this.project.id):this.account&&localStorage.removeItem(p+"-"+this.account.id)),window.location.replace("/?a="+e)}async switchProject(e){this.account&&localStorage.setItem(p+"-"+this.account.id,e),window.location.replace("/?a="+this.account?.id+"&p="+e)}async _loadTypes(){if(this.project)return this.store.types.list({},{layout:!0}).then((e=>this.typeRegistry=new P(e))).catch((e=>{throw console.error("Failed to fetch object types",e),e}));console.log("No project selected")}async reloadTypes(){return this._loadTypes().then((()=>{this.setSession?.(this.clone())}))}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 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 $(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.typeRegistry=this.typeRegistry,e.onboardingComplete=this.onboardingComplete,e}}const U=a(void 0);function C(){const e=c(U);if(!e)throw new Error("useUserSession must be used within a UserSessionProvider");return e}const N="auth_state",L="auth_state_expiry";const R=[".composable.sh",".vertesia.dev","vertesia.app"];function D({children:e}){const o=new URLSearchParams(location.hash.substring(1)),r=o.get("token"),n=o.get("state"),[i,a]=u(new $),{generateState:c,verifyState:d}={generateState:l((()=>{const e=crypto.randomUUID(),t=Date.now()+3e5;return sessionStorage.setItem(N,e),sessionStorage.setItem(L,t.toString()),e}),[]),verifyState:l((e=>{if(!e)return"Missing state";const t=sessionStorage.getItem(N),o=parseInt(sessionStorage.getItem(L)||"0");let r;return r=t!==e?`State mismatched (${t} !== ${e})`:Date.now()>o?"State expired":void 0,sessionStorage.removeItem(N),sessionStorage.removeItem(L),r}),[]),clearState:l((()=>{sessionStorage.removeItem(N),sessionStorage.removeItem(L)}),[])},f=(e,t)=>{const o=new URL("https://internal-auth.vertesia.app/"),r=new URL(window.location.href);r.hash="",o.searchParams.set("redirect_uri",r.toString()),o.searchParams.set("state",c()),location.replace(o.toString())};return h((()=>{console.log("Auth: starting auth flow"),t.logger.info("Starting auth flow");const e=new URL(window.location.href),o=e.searchParams.get("a")??localStorage.getItem(m)??void 0,c=e.searchParams.get("p")??localStorage.getItem(p+"-"+o)??void 0;if(console.log("Auth: selected account",o),console.log("Auth: selected project",c),t.logger.info("Selected account and project",{vertesia:{account_id:o,project_id:c}}),r&&n){const e=d(n);return e&&(console.error(`Auth: invalid state: ${e}`),t.logger.error(`Invalid state: ${e}`,{vertesia:{state:n}}),f()),void A(o,c,r).then((e=>{i.login(e.rawToken).then((()=>{a(i.clone()),window.location.hash=""}))})).catch((e=>{console.error("Failed to fetch user token from studio, redirecting to central auth",e),t.logger.error("Failed to fetch user token from studio, redirecting to central auth",{vertesia:{error:e}}),f()}))}return i.isLoggedIn()||(console.log("Auth: not logged in & no token/state"),t.logger.info("Not logged in & no token/state",{vertesia:{account_id:o,project_id:c}}),t.isDocker||R.some((e=>window.location.hostname.endsWith(e)))?(console.log("Auth: on dev domain, redirecting to central auth with selection",o,c),t.logger.info("Redirecting to central auth with selection",{vertesia:{account_id:o,project_id:c}}),f()):(console.log("Auth: not on dev domain"),t.logger.info("Not on dev domain",{vertesia:{account_id:o,project_id:c}}))),s(T(),(async e=>{e?(console.log("Auth: successful login with firebase"),t.logger.info("Successful login with firebase",{vertesia:{account_id:o,project_id:c}}),i.setSession=a,await A(o,c).then((e=>{i.login(e.rawToken).then((()=>a(i.clone())))})).catch((e=>{console.error("Failed to fetch user token from studio",e),t.logger.error("Failed to fetch user token from studio",{vertesia:{account_id:o,project_id:c,error:e}}),e instanceof E||i.logout(),i.isLoading=!1,i.authError=e,a(i.clone())}))):(console.log("Auth: using anonymous user"),t.logger.info("Using anonymous user",{vertesia:{account_id:o,project_id:c}}),i.client.withAuthCallback(void 0),i.logout(),a(i.clone()))}))}),[]),g(U.Provider,{value:i,children:e})}function x(){return{tagUserSession:async e=>{const t=window.localStorage.getItem("composableSignupData");e?t&&window.localStorage.removeItem("composableSignupData"):console.error("No user found -- skipping tagging")},trackEvent:(e,o)=>{t.isProd||console.debug("track event",e,o),r(y(),e,{...o,debug_mode:!t.isProd})}}}export{m as LastSelectedAccountId_KEY,p as LastSelectedProjectId_KEY,P as TypeRegistry,E as UserNotFoundError,$ as UserSession,U as UserSessionContext,D as UserSessionProvider,j as fetchComposableToken,F as fetchComposableTokenFromFirebaseToken,A as getComposableToken,y as getFirebaseAnalytics,S as getFirebaseApp,T as getFirebaseAuth,I as getFirebaseAuthToken,_ as setFirebaseTenant,x as useUXTracking,C as useUserSession};
|
|
2
2
|
//# sourceMappingURL=vertesia-ui-session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertesia-ui-session.js","sources":["esm/session/auth/firebase.js","esm/session/TypeRegistry.js","esm/session/UserSession.js","esm/session/auth/composable.js","esm/session/auth/useAuthState.js","esm/session/UserSessionProvider.js","esm/session/useUXTracking.js"],"sourcesContent":["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 _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 }\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 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 (parseError) {\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 && 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","export class TypeRegistry {\n types;\n map = {};\n constructor(types) {\n this.types = types;\n //sort types\n types.sort((a, b) => a.name.localeCompare(b.name));\n for (const type of types) {\n this.map[type.id] = type;\n }\n }\n getType(id) {\n return this.map[id];\n }\n getTypeLayout(id) {\n const type = this.map[id];\n return type ? type.table_layout : undefined;\n }\n getTypeName(id) {\n const type = this.map[id];\n return type ? type.name : undefined;\n }\n}\n//# sourceMappingURL=TypeRegistry.js.map","import { jwtDecode } from 'jwt-decode';\nimport { createContext, useContext } from 'react';\nimport { VertesiaClient } from '@vertesia/client';\nimport { Env } from '@vertesia/ui/env';\nimport { getComposableToken } from './auth/composable';\nimport { getFirebaseAuth } from './auth/firebase';\nimport { TypeRegistry } from './TypeRegistry';\nexport const LastSelectedAccountId_KEY = 'composableai.lastSelectedAccountId';\nexport const LastSelectedProjectId_KEY = 'composableai.lastSelectedProjectId';\nclass UserSession {\n isLoading = true;\n client;\n authError;\n authToken;\n typeRegistry;\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 });\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 return this.authToken;\n }\n get account() {\n return this.authToken?.account;\n }\n get project() {\n return this.authToken?.project;\n }\n get accounts() {\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 this.logout();\n }\n getAccount() {\n return this.authToken?.account;\n }\n async login(token) {\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 // Independent async calls\n await Promise.all([\n this._loadTypes(),\n this.fetchOnboardingStatus(),\n ]);\n return Promise.resolve();\n }\n isLoggedIn() {\n return !!this.authToken;\n }\n logout() {\n console.log('Logging out');\n if (this.authToken) {\n getFirebaseAuth().signOut();\n }\n this.authError = undefined;\n this.isLoading = false;\n this.authToken = undefined;\n this.typeRegistry = undefined;\n this.setSession = undefined;\n this.client.withAuthCallback(undefined);\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 _loadTypes() {\n if (this.project) {\n return this.store.types.list({}, { layout: true }).then(types => this.typeRegistry = new TypeRegistry(types)).catch(err => {\n console.error('Failed to fetch object types', err);\n throw err;\n });\n }\n else {\n console.log('No project selected');\n }\n }\n async reloadTypes() {\n return this._loadTypes().then(() => {\n this.setSession?.(this.clone());\n });\n }\n async fetchAccounts() {\n return this.client.accounts.list().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 }).catch(err => {\n console.error('Failed to fetch accounts', 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.typeRegistry = this.typeRegistry;\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 { jwtDecode } from \"jwt-decode\";\nimport { Env } from '@vertesia/ui/env';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from '../UserSession';\nimport { getFirebaseAuth, getFirebaseAuthToken } from './firebase';\nlet AUTH_TOKEN_RAW;\nlet AUTH_TOKEN;\nexport async function fetchComposableToken(getIdToken, accountId, projectId, ttl) {\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 },\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 console.log('Fetching composable token from ' + Env.endpoints.studio);\n Env.logger.info('Fetching composable token from' + Env.endpoints.studio, {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n const url = new URL(Env.endpoints.studio + '/auth/token');\n if (accountId)\n url.searchParams.set('accountId', accountId);\n if (projectId)\n url.searchParams.set('projectId', projectId);\n if (ttl)\n url.searchParams.set('ttl', String(ttl));\n console.log(`Getting composable token for account ${accountId} and project ${projectId}`);\n Env.logger.info('Getting composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`\n }\n }).catch(err => {\n localStorage.removeItem(LastSelectedAccountId_KEY);\n localStorage.removeItem(LastSelectedProjectId_KEY);\n console.error('Failed to get composable token', err);\n Env.logger.error('Failed to get composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: err,\n },\n });\n throw new Error('Failed to get composable token');\n });\n if (idToken && res?.status === 412) {\n console.log(\"412: auth succeeded but user doesn't exist - signup required\", res?.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: res?.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 (!res || !res.ok) {\n console.error('Failed to get composable token', res);\n Env.logger.error('Failed to get composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: res?.status,\n },\n });\n throw new Error('Failed to get composable token');\n }\n const { token } = await res.json().catch(err => {\n Env.logger.error('Failed to parse composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: err,\n },\n });\n console.error('Failed to parse composable token', err);\n });\n return token;\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}\nexport async function getComposableToken(accountId, projectId, initToken, forceRefresh = 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 (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 || !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}\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');\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 // Clear stored state regardless of outcome\n sessionStorage.removeItem(AUTH_STATE_KEY);\n sessionStorage.removeItem(STATE_EXPIRY_KEY);\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","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { onAuthStateChanged } from \"firebase/auth\";\nimport { useEffect, useState } from \"react\";\nimport { UserNotFoundError, getComposableToken } from \"./auth/composable\";\nimport { getFirebaseAuth } from \"./auth/firebase\";\nimport { useAuthState } from \"./auth/useAuthState\";\nimport { Env } from \"@vertesia/ui/env\";\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY, UserSession, UserSessionContext } from \"./UserSession\";\nconst devDomains = [\".composable.sh\", \".vertesia.dev\", \"vertesia.app\"];\nconst CENTRAL_AUTH_REDIRECT = \"https://internal-auth.vertesia.app/\";\nfunction shouldRedirectToCentralAuth() {\n // Authentication is not supported in Docker environment.\n // See https://github.com/vertesia/studio/wiki/Composable-UI-Hosting-Options\n if (Env.isDocker) {\n return true;\n }\n return devDomains.some((domain) => window.location.hostname.endsWith(domain));\n}\nexport function UserSessionProvider({ children }) {\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 } = useAuthState();\n const redirectToCentralAuth = (projectId, accountId) => {\n const url = new URL(CENTRAL_AUTH_REDIRECT);\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 useEffect(() => {\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 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 getComposableToken(selectedAccount, selectedProject, token)\n .then((res) => {\n session.login(res.rawToken).then(() => {\n setSession(session.clone());\n //cleanup the hash\n window.location.hash = \"\";\n });\n })\n .catch((err) => {\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 on a dev domain and not logged in, redirect to central auth\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: on dev domain, 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 }\n else {\n console.log(\"Auth: not on dev domain\");\n Env.logger.info(\"Not on dev domain\", {\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)\n .then((res) => {\n session.login(res.rawToken).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 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":["_firebaseApp","_analytics","_firebaseAuth","getFirebaseApp","initializeApp","Env","firebase","error","console","Error","getFirebaseAnalytics","getAnalytics","getFirebaseAuth","getAuth","async","setFirebaseTenant","tenantEmail","log","retries","retryDelay","response","fetch","method","headers","body","JSON","stringify","signal","AbortSignal","timeout","ok","errorData","json","parseError","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","TypeRegistry","types","map","constructor","this","sort","a","b","name","localeCompare","type","id","getType","getTypeLayout","table_layout","undefined","getTypeName","LastSelectedAccountId_KEY","LastSelectedProjectId_KEY","UserSession","isLoading","client","authError","authToken","typeRegistry","setSession","lastSelectedAccount","lastSelectedProject","onboardingComplete","VertesiaClient","serverUrl","endpoints","studio","storeUrl","zeno","logout","bind","store","account","project","accounts","authCallback","rawAuthToken","getComposableToken","res","rawToken","jwtDecode","signOut","getAccount","login","withAuthCallback","localStorage","setItem","onLogin","all","_loadTypes","fetchOnboardingStatus","isLoggedIn","switchAccount","targetAccountId","removeItem","window","location","replace","switchProject","targetProjectId","list","layout","reloadTypes","clone","fetchAccounts","previousStatus","onboarding","onboardingProgress","Object","values","every","value","session","UserSessionContext","createContext","useUserSession","useContext","AUTH_TOKEN_RAW","AUTH_TOKEN","fetchComposableToken","accountId","projectId","ttl","account_id","project_id","idToken","url","URL","searchParams","set","String","Authorization","idTokenDecoded","UserNotFoundError","fetchComposableTokenFromFirebaseToken","initToken","forceRefresh","selectedAccount","getItem","selectedProject","exp","Date","now","super","AUTH_STATE_KEY","STATE_EXPIRY_KEY","devDomains","UserSessionProvider","children","hashParams","URLSearchParams","hash","substring","get","state","useState","generateState","verifyState","useCallback","crypto","randomUUID","expiryTime","sessionStorage","toString","returnedState","savedState","parseInt","reason","clearState","redirectToCentralAuth","currentUrl","href","useEffect","validationError","isDocker","some","domain","hostname","endsWith","onAuthStateChanged","firebaseUser","_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":["esm/session/constants.js","esm/session/auth/firebase.js","esm/session/auth/composable.js","esm/session/TypeRegistry.js","esm/session/UserSession.js","esm/session/auth/useAuthState.js","esm/session/UserSessionProvider.js","esm/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 _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 }\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 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 (parseError) {\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 && 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 { jwtDecode } from \"jwt-decode\";\nimport { Env } from '@vertesia/ui/env';\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) {\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 },\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 console.log('Fetching composable token from ' + Env.endpoints.studio);\n Env.logger.info('Fetching composable token from' + Env.endpoints.studio, {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n const url = new URL(Env.endpoints.studio + '/auth/token');\n if (accountId)\n url.searchParams.set('accountId', accountId);\n if (projectId)\n url.searchParams.set('projectId', projectId);\n if (ttl)\n url.searchParams.set('ttl', String(ttl));\n console.log(`Getting composable token for account ${accountId} and project ${projectId}`);\n Env.logger.info('Getting composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n },\n });\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`\n }\n }).catch(err => {\n localStorage.removeItem(LastSelectedAccountId_KEY);\n localStorage.removeItem(LastSelectedProjectId_KEY);\n console.error('Failed to get composable token', err);\n Env.logger.error('Failed to get composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: err,\n },\n });\n throw new Error('Failed to get composable token');\n });\n if (idToken && res?.status === 412) {\n console.log(\"412: auth succeeded but user doesn't exist - signup required\", res?.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: res?.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 (!res || !res.ok) {\n console.error('Failed to get composable token', res);\n Env.logger.error('Failed to get composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n status: res?.status,\n },\n });\n throw new Error('Failed to get composable token');\n }\n const { token } = await res.json().catch(err => {\n Env.logger.error('Failed to parse composable token', {\n vertesia: {\n account_id: accountId,\n project_id: projectId,\n error: err,\n },\n });\n console.error('Failed to parse composable token', err);\n });\n return token;\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}\nexport async function getComposableToken(accountId, projectId, initToken, forceRefresh = 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 (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 || !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}\n//# sourceMappingURL=composable.js.map","export class TypeRegistry {\n types;\n map = {};\n constructor(types) {\n this.types = types;\n //sort types\n types.sort((a, b) => a.name.localeCompare(b.name));\n for (const type of types) {\n this.map[type.id] = type;\n }\n }\n getType(id) {\n return this.map[id];\n }\n getTypeLayout(id) {\n const type = this.map[id];\n return type ? type.table_layout : undefined;\n }\n getTypeName(id) {\n const type = this.map[id];\n return type ? type.name : undefined;\n }\n}\n//# sourceMappingURL=TypeRegistry.js.map","import { jwtDecode } from 'jwt-decode';\nimport { createContext, useContext } from 'react';\nimport { VertesiaClient } from '@vertesia/client';\nimport { Env } from '@vertesia/ui/env';\nimport { getComposableToken } from './auth/composable';\nimport { getFirebaseAuth } from './auth/firebase';\nimport { TypeRegistry } from './TypeRegistry';\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from './constants';\nexport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY };\nclass UserSession {\n isLoading = true;\n client;\n authError;\n authToken;\n typeRegistry;\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 });\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 return this.authToken;\n }\n get account() {\n return this.authToken?.account;\n }\n get project() {\n return this.authToken?.project;\n }\n get accounts() {\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 this.logout();\n }\n getAccount() {\n return this.authToken?.account;\n }\n async login(token) {\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 // Independent async calls\n await Promise.all([\n this._loadTypes(),\n this.fetchOnboardingStatus(),\n ]);\n return Promise.resolve();\n }\n isLoggedIn() {\n return !!this.authToken;\n }\n logout() {\n console.log('Logging out');\n if (this.authToken) {\n getFirebaseAuth().signOut();\n }\n this.authError = undefined;\n this.isLoading = false;\n this.authToken = undefined;\n this.typeRegistry = undefined;\n this.setSession = undefined;\n this.client.withAuthCallback(undefined);\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 _loadTypes() {\n if (this.project) {\n return this.store.types.list({}, { layout: true }).then(types => this.typeRegistry = new TypeRegistry(types)).catch(err => {\n console.error('Failed to fetch object types', err);\n throw err;\n });\n }\n else {\n console.log('No project selected');\n }\n }\n async reloadTypes() {\n return this._loadTypes().then(() => {\n this.setSession?.(this.clone());\n });\n }\n async fetchAccounts() {\n return this.client.accounts.list().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 }).catch(err => {\n console.error('Failed to fetch accounts', 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.typeRegistry = this.typeRegistry;\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","/**\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');\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 // Clear stored state regardless of outcome\n sessionStorage.removeItem(AUTH_STATE_KEY);\n sessionStorage.removeItem(STATE_EXPIRY_KEY);\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","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { onAuthStateChanged } from \"firebase/auth\";\nimport { useEffect, useState } from \"react\";\nimport { UserNotFoundError, getComposableToken } from \"./auth/composable\";\nimport { getFirebaseAuth } from \"./auth/firebase\";\nimport { useAuthState } from \"./auth/useAuthState\";\nimport { Env } from \"@vertesia/ui/env\";\nimport { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY, UserSession, UserSessionContext } from \"./UserSession\";\nconst devDomains = [\".composable.sh\", \".vertesia.dev\", \"vertesia.app\"];\nconst CENTRAL_AUTH_REDIRECT = \"https://internal-auth.vertesia.app/\";\nfunction shouldRedirectToCentralAuth() {\n // Authentication is not supported in Docker environment.\n // See https://github.com/vertesia/studio/wiki/Composable-UI-Hosting-Options\n if (Env.isDocker) {\n return true;\n }\n return devDomains.some((domain) => window.location.hostname.endsWith(domain));\n}\nexport function UserSessionProvider({ children }) {\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 } = useAuthState();\n const redirectToCentralAuth = (projectId, accountId) => {\n const url = new URL(CENTRAL_AUTH_REDIRECT);\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 useEffect(() => {\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 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 getComposableToken(selectedAccount, selectedProject, token)\n .then((res) => {\n session.login(res.rawToken).then(() => {\n setSession(session.clone());\n //cleanup the hash\n window.location.hash = \"\";\n });\n })\n .catch((err) => {\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 on a dev domain and not logged in, redirect to central auth\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: on dev domain, 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 }\n else {\n console.log(\"Auth: not on dev domain\");\n Env.logger.info(\"Not on dev domain\", {\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)\n .then((res) => {\n session.login(res.rawToken).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 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","initializeApp","Env","firebase","error","console","Error","getFirebaseAnalytics","getAnalytics","getFirebaseAuth","getAuth","async","setFirebaseTenant","tenantEmail","log","retries","retryDelay","response","fetch","method","headers","body","JSON","stringify","signal","AbortSignal","timeout","ok","errorData","json","parseError","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","account_id","project_id","idToken","endpoints","studio","url","URL","searchParams","set","String","res","Authorization","localStorage","removeItem","idTokenDecoded","jwtDecode","UserNotFoundError","fetchComposableTokenFromFirebaseToken","getComposableToken","initToken","forceRefresh","selectedAccount","getItem","undefined","selectedProject","exp","Date","now","rawToken","constructor","super","this","name","TypeRegistry","types","map","sort","a","b","localeCompare","type","id","getType","getTypeLayout","table_layout","getTypeName","UserSession","isLoading","client","authError","authToken","typeRegistry","setSession","lastSelectedAccount","lastSelectedProject","onboardingComplete","VertesiaClient","serverUrl","storeUrl","zeno","logout","bind","store","account","project","accounts","authCallback","rawAuthToken","signOut","getAccount","login","withAuthCallback","setItem","onLogin","all","_loadTypes","fetchOnboardingStatus","isLoggedIn","switchAccount","targetAccountId","window","location","replace","switchProject","targetProjectId","list","layout","reloadTypes","clone","fetchAccounts","previousStatus","onboarding","onboardingProgress","Object","values","every","value","session","UserSessionContext","createContext","useUserSession","useContext","AUTH_STATE_KEY","STATE_EXPIRY_KEY","devDomains","UserSessionProvider","children","hashParams","URLSearchParams","hash","substring","get","state","useState","generateState","verifyState","useCallback","crypto","randomUUID","expiryTime","sessionStorage","toString","returnedState","savedState","parseInt","reason","clearState","redirectToCentralAuth","currentUrl","href","useEffect","validationError","isDocker","some","domain","hostname","endsWith","onAuthStateChanged","firebaseUser","_jsx","Provider","useUXTracking","tagUserSession","signupData","trackEvent","eventName","eventProperties","isProd","debug","logEvent","debug_mode"],"mappings":"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"}
|