@orthacms/users-admin 0.0.0-reserve.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/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/lib/api/useAddWorkspaceMember/index.d.ts +16 -0
- package/dist/lib/api/useAddWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/api/useInviteMember/index.d.ts +17 -0
- package/dist/lib/api/useInviteMember/index.d.ts.map +1 -0
- package/dist/lib/api/useMembers/index.d.ts +15 -0
- package/dist/lib/api/useMembers/index.d.ts.map +1 -0
- package/dist/lib/api/useMembersMutation/index.d.ts +13 -0
- package/dist/lib/api/useMembersMutation/index.d.ts.map +1 -0
- package/dist/lib/api/useRemoveWorkspaceMember/index.d.ts +15 -0
- package/dist/lib/api/useRemoveWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/api/useResendInvite/index.d.ts +8 -0
- package/dist/lib/api/useResendInvite/index.d.ts.map +1 -0
- package/dist/lib/api/useRevokeInvite/index.d.ts +7 -0
- package/dist/lib/api/useRevokeInvite/index.d.ts.map +1 -0
- package/dist/lib/api/useRevokeSession/index.d.ts +15 -0
- package/dist/lib/api/useRevokeSession/index.d.ts.map +1 -0
- package/dist/lib/api/useSetMemberStatus/index.d.ts +15 -0
- package/dist/lib/api/useSetMemberStatus/index.d.ts.map +1 -0
- package/dist/lib/api/useUpdateMember/index.d.ts +15 -0
- package/dist/lib/api/useUpdateMember/index.d.ts.map +1 -0
- package/dist/lib/api/useUserDetail/index.d.ts +9 -0
- package/dist/lib/api/useUserDetail/index.d.ts.map +1 -0
- package/dist/lib/api/useUserSessions/index.d.ts +25 -0
- package/dist/lib/api/useUserSessions/index.d.ts.map +1 -0
- package/dist/lib/api/useWorkspaceOptions/index.d.ts +18 -0
- package/dist/lib/api/useWorkspaceOptions/index.d.ts.map +1 -0
- package/dist/lib/application/useAddWorkspaceMember/index.d.ts +11 -0
- package/dist/lib/application/useAddWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/application/useAddWorkspaceMember/index.js +21 -0
- package/dist/lib/application/useInviteMember/index.d.ts +12 -0
- package/dist/lib/application/useInviteMember/index.d.ts.map +1 -0
- package/dist/lib/application/useInviteMember/index.js +12 -0
- package/dist/lib/application/useInviteMemberFlow/index.d.ts +59 -0
- package/dist/lib/application/useInviteMemberFlow/index.d.ts.map +1 -0
- package/dist/lib/application/useInviteMemberFlow/index.js +47 -0
- package/dist/lib/application/useIssuePasswordReset/index.d.ts +12 -0
- package/dist/lib/application/useIssuePasswordReset/index.d.ts.map +1 -0
- package/dist/lib/application/useIssuePasswordReset/index.js +14 -0
- package/dist/lib/application/useMembers/index.d.ts +15 -0
- package/dist/lib/application/useMembers/index.d.ts.map +1 -0
- package/dist/lib/application/useMembers/index.js +23 -0
- package/dist/lib/application/useMembersMutation/index.d.ts +14 -0
- package/dist/lib/application/useMembersMutation/index.d.ts.map +1 -0
- package/dist/lib/application/useMembersMutation/index.js +25 -0
- package/dist/lib/application/usePreferences/index.d.ts +15 -0
- package/dist/lib/application/usePreferences/index.d.ts.map +1 -0
- package/dist/lib/application/usePreferences/index.js +28 -0
- package/dist/lib/application/useRemoveWorkspaceMember/index.d.ts +10 -0
- package/dist/lib/application/useRemoveWorkspaceMember/index.d.ts.map +1 -0
- package/dist/lib/application/useRemoveWorkspaceMember/index.js +20 -0
- package/dist/lib/application/useResendInvite/index.d.ts +10 -0
- package/dist/lib/application/useResendInvite/index.d.ts.map +1 -0
- package/dist/lib/application/useResendInvite/index.js +12 -0
- package/dist/lib/application/useRevokeInvite/index.d.ts +7 -0
- package/dist/lib/application/useRevokeInvite/index.d.ts.map +1 -0
- package/dist/lib/application/useRevokeInvite/index.js +10 -0
- package/dist/lib/application/useRevokeSession/index.d.ts +10 -0
- package/dist/lib/application/useRevokeSession/index.d.ts.map +1 -0
- package/dist/lib/application/useRevokeSession/index.js +19 -0
- package/dist/lib/application/useSetMemberStatus/index.d.ts +11 -0
- package/dist/lib/application/useSetMemberStatus/index.d.ts.map +1 -0
- package/dist/lib/application/useSetMemberStatus/index.js +11 -0
- package/dist/lib/application/useUpdateMember/index.d.ts +11 -0
- package/dist/lib/application/useUpdateMember/index.d.ts.map +1 -0
- package/dist/lib/application/useUpdateMember/index.js +11 -0
- package/dist/lib/application/useUpdateTheme/index.d.ts +14 -0
- package/dist/lib/application/useUpdateTheme/index.d.ts.map +1 -0
- package/dist/lib/application/useUpdateTheme/index.js +25 -0
- package/dist/lib/application/useUserDetail/index.d.ts +9 -0
- package/dist/lib/application/useUserDetail/index.d.ts.map +1 -0
- package/dist/lib/application/useUserDetail/index.js +17 -0
- package/dist/lib/application/useUserSessions/index.d.ts +9 -0
- package/dist/lib/application/useUserSessions/index.d.ts.map +1 -0
- package/dist/lib/application/useUserSessions/index.js +17 -0
- package/dist/lib/application/useWorkspaceOptions/index.d.ts +10 -0
- package/dist/lib/application/useWorkspaceOptions/index.d.ts.map +1 -0
- package/dist/lib/application/useWorkspaceOptions/index.js +17 -0
- package/dist/lib/components/AccountMenu/index.d.ts +9 -0
- package/dist/lib/components/AccountMenu/index.d.ts.map +1 -0
- package/dist/lib/components/AddToWorkspacesDialog/index.d.ts +19 -0
- package/dist/lib/components/AddToWorkspacesDialog/index.d.ts.map +1 -0
- package/dist/lib/components/BackLink/index.d.ts +14 -0
- package/dist/lib/components/BackLink/index.d.ts.map +1 -0
- package/dist/lib/components/ConfirmDialog/index.d.ts +30 -0
- package/dist/lib/components/ConfirmDialog/index.d.ts.map +1 -0
- package/dist/lib/components/EditMemberDialog/index.d.ts +21 -0
- package/dist/lib/components/EditMemberDialog/index.d.ts.map +1 -0
- package/dist/lib/components/MemberAvatar/index.d.ts +24 -0
- package/dist/lib/components/MemberAvatar/index.d.ts.map +1 -0
- package/dist/lib/components/MembersEmpty/index.d.ts +16 -0
- package/dist/lib/components/MembersEmpty/index.d.ts.map +1 -0
- package/dist/lib/components/MembersNoAccess/index.d.ts +7 -0
- package/dist/lib/components/MembersNoAccess/index.d.ts.map +1 -0
- package/dist/lib/components/MembersPagination/index.d.ts +17 -0
- package/dist/lib/components/MembersPagination/index.d.ts.map +1 -0
- package/dist/lib/components/MembersSkeleton/index.d.ts +32 -0
- package/dist/lib/components/MembersSkeleton/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberRoleChip/index.d.ts +10 -0
- package/dist/lib/components/MembersTable/MemberRoleChip/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberRowActions/index.d.ts +16 -0
- package/dist/lib/components/MembersTable/MemberRowActions/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberStatusBadge/index.d.ts +10 -0
- package/dist/lib/components/MembersTable/MemberStatusBadge/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/MemberWorkspaces/index.d.ts +10 -0
- package/dist/lib/components/MembersTable/MemberWorkspaces/index.d.ts.map +1 -0
- package/dist/lib/components/MembersTable/index.d.ts +12 -0
- package/dist/lib/components/MembersTable/index.d.ts.map +1 -0
- package/dist/lib/components/MembersToolbar/index.d.ts +13 -0
- package/dist/lib/components/MembersToolbar/index.d.ts.map +1 -0
- package/dist/lib/components/RolePicker/index.d.ts +18 -0
- package/dist/lib/components/RolePicker/index.d.ts.map +1 -0
- package/dist/lib/components/SessionCard/index.d.ts +15 -0
- package/dist/lib/components/SessionCard/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserDetailTabs/index.d.ts +13 -0
- package/dist/lib/components/UserDetailLayout/UserDetailTabs/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserHero/index.d.ts +10 -0
- package/dist/lib/components/UserDetailLayout/UserHero/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserSideRail/index.d.ts +12 -0
- package/dist/lib/components/UserDetailLayout/UserSideRail/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/UserStatsStrip/index.d.ts +10 -0
- package/dist/lib/components/UserDetailLayout/UserStatsStrip/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailLayout/index.d.ts +13 -0
- package/dist/lib/components/UserDetailLayout/index.d.ts.map +1 -0
- package/dist/lib/components/UserDetailRouter/index.d.ts +13 -0
- package/dist/lib/components/UserDetailRouter/index.d.ts.map +1 -0
- package/dist/lib/components/WorkspaceMembershipCard/index.d.ts +15 -0
- package/dist/lib/components/WorkspaceMembershipCard/index.d.ts.map +1 -0
- package/dist/lib/domain/member/index.d.ts +61 -0
- package/dist/lib/domain/member/index.d.ts.map +1 -0
- package/dist/lib/domain/member/index.js +61 -0
- package/dist/lib/domain/types/member/index.d.ts +90 -0
- package/dist/lib/domain/types/member/index.d.ts.map +1 -0
- package/dist/lib/domain/types/member/index.js +1 -0
- package/dist/lib/domain/types/session/index.d.ts +18 -0
- package/dist/lib/domain/types/session/index.d.ts.map +1 -0
- package/dist/lib/domain/types/session/index.js +1 -0
- package/dist/lib/domain/types/workspaceOption/index.d.ts +15 -0
- package/dist/lib/domain/types/workspaceOption/index.d.ts.map +1 -0
- package/dist/lib/domain/types/workspaceOption/index.js +1 -0
- package/dist/lib/domain/value-objects/email/index.d.ts +24 -0
- package/dist/lib/domain/value-objects/email/index.d.ts.map +1 -0
- package/dist/lib/domain/value-objects/email/index.js +45 -0
- package/dist/lib/infrastructure/httpMemberGateway/index.d.ts +12 -0
- package/dist/lib/infrastructure/httpMemberGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/httpMemberGateway/index.js +158 -0
- package/dist/lib/infrastructure/inviteLink/index.d.ts +13 -0
- package/dist/lib/infrastructure/inviteLink/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/inviteLink/index.js +23 -0
- package/dist/lib/infrastructure/memberGateway/index.d.ts +103 -0
- package/dist/lib/infrastructure/memberGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/memberGateway/index.js +1 -0
- package/dist/lib/infrastructure/memberMapper/index.d.ts +59 -0
- package/dist/lib/infrastructure/memberMapper/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/memberMapper/index.js +52 -0
- package/dist/lib/infrastructure/membersKeys/index.d.ts +37 -0
- package/dist/lib/infrastructure/membersKeys/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/membersKeys/index.js +25 -0
- package/dist/lib/infrastructure/passwordResetLink/index.d.ts +13 -0
- package/dist/lib/infrastructure/passwordResetLink/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/passwordResetLink/index.js +24 -0
- package/dist/lib/infrastructure/preferencesGateway/index.d.ts +37 -0
- package/dist/lib/infrastructure/preferencesGateway/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/preferencesGateway/index.js +43 -0
- package/dist/lib/pages/InviteMemberPage/index.d.ts +7 -0
- package/dist/lib/pages/InviteMemberPage/index.d.ts.map +1 -0
- package/dist/lib/pages/MembersPage/index.d.ts +13 -0
- package/dist/lib/pages/MembersPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserAccessPage/index.d.ts +9 -0
- package/dist/lib/pages/UserAccessPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserActivityPage/index.d.ts +8 -0
- package/dist/lib/pages/UserActivityPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserGeneralPage/index.d.ts +7 -0
- package/dist/lib/pages/UserGeneralPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserRolesPage/index.d.ts +8 -0
- package/dist/lib/pages/UserRolesPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserSessionsPage/index.d.ts +7 -0
- package/dist/lib/pages/UserSessionsPage/index.d.ts.map +1 -0
- package/dist/lib/pages/UserWorkspacesPage/index.d.ts +8 -0
- package/dist/lib/pages/UserWorkspacesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/AccountMenu/index.d.ts +9 -0
- package/dist/lib/presentation/components/AccountMenu/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/AccountMenu/index.js +42 -0
- package/dist/lib/presentation/components/AddToWorkspacesDialog/index.d.ts +19 -0
- package/dist/lib/presentation/components/AddToWorkspacesDialog/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/AddToWorkspacesDialog/index.js +89 -0
- package/dist/lib/presentation/components/BackLink/index.d.ts +14 -0
- package/dist/lib/presentation/components/BackLink/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/BackLink/index.js +12 -0
- package/dist/lib/presentation/components/InviteLinkDialog/index.d.ts +25 -0
- package/dist/lib/presentation/components/InviteLinkDialog/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/InviteLinkDialog/index.js +77 -0
- package/dist/lib/presentation/components/InviteLinkPanel/index.d.ts +26 -0
- package/dist/lib/presentation/components/InviteLinkPanel/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/InviteLinkPanel/index.js +59 -0
- package/dist/lib/presentation/components/InviteSent/index.d.ts +20 -0
- package/dist/lib/presentation/components/InviteSent/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/InviteSent/index.js +60 -0
- package/dist/lib/presentation/components/MemberAvatar/index.d.ts +24 -0
- package/dist/lib/presentation/components/MemberAvatar/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MemberAvatar/index.js +14 -0
- package/dist/lib/presentation/components/MembersEmpty/index.d.ts +16 -0
- package/dist/lib/presentation/components/MembersEmpty/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersEmpty/index.js +42 -0
- package/dist/lib/presentation/components/MembersNoAccess/index.d.ts +7 -0
- package/dist/lib/presentation/components/MembersNoAccess/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersNoAccess/index.js +24 -0
- package/dist/lib/presentation/components/MembersPagination/index.d.ts +17 -0
- package/dist/lib/presentation/components/MembersPagination/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersPagination/index.js +45 -0
- package/dist/lib/presentation/components/MembersSkeleton/index.d.ts +32 -0
- package/dist/lib/presentation/components/MembersSkeleton/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersSkeleton/index.js +61 -0
- package/dist/lib/presentation/components/MembersTable/MemberRoleChip/index.d.ts +17 -0
- package/dist/lib/presentation/components/MembersTable/MemberRoleChip/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberRoleChip/index.js +36 -0
- package/dist/lib/presentation/components/MembersTable/MemberRowActions/index.d.ts +16 -0
- package/dist/lib/presentation/components/MembersTable/MemberRowActions/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberRowActions/index.js +284 -0
- package/dist/lib/presentation/components/MembersTable/MemberStatusBadge/index.d.ts +10 -0
- package/dist/lib/presentation/components/MembersTable/MemberStatusBadge/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberStatusBadge/index.js +49 -0
- package/dist/lib/presentation/components/MembersTable/MemberWorkspaces/index.d.ts +10 -0
- package/dist/lib/presentation/components/MembersTable/MemberWorkspaces/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/MemberWorkspaces/index.js +37 -0
- package/dist/lib/presentation/components/MembersTable/index.d.ts +12 -0
- package/dist/lib/presentation/components/MembersTable/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersTable/index.js +54 -0
- package/dist/lib/presentation/components/MembersTable/membersTableAnchor/index.d.ts +14 -0
- package/dist/lib/presentation/components/MembersTable/membersTableAnchor/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersToolbar/index.d.ts +15 -0
- package/dist/lib/presentation/components/MembersToolbar/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/MembersToolbar/index.js +23 -0
- package/dist/lib/presentation/components/PasswordResetCard/index.d.ts +19 -0
- package/dist/lib/presentation/components/PasswordResetCard/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/PasswordResetCard/index.js +109 -0
- package/dist/lib/presentation/components/PasswordResetLinkDialog/index.d.ts +27 -0
- package/dist/lib/presentation/components/PasswordResetLinkDialog/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/PasswordResetLinkDialog/index.js +79 -0
- package/dist/lib/presentation/components/PasswordResetLinkPanel/index.d.ts +31 -0
- package/dist/lib/presentation/components/PasswordResetLinkPanel/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/PasswordResetLinkPanel/index.js +64 -0
- package/dist/lib/presentation/components/RolePicker/index.d.ts +21 -0
- package/dist/lib/presentation/components/RolePicker/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/RolePicker/index.js +51 -0
- package/dist/lib/presentation/components/SessionCard/index.d.ts +15 -0
- package/dist/lib/presentation/components/SessionCard/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/SessionCard/index.js +43 -0
- package/dist/lib/presentation/components/ThemeSync/index.d.ts +21 -0
- package/dist/lib/presentation/components/ThemeSync/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/ThemeSync/index.js +32 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserDetailTabs/index.d.ts +15 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserDetailTabs/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserDetailTabs/index.js +52 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserHero/index.d.ts +10 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserHero/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserHero/index.js +26 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserStatsStrip/index.d.ts +10 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserStatsStrip/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/UserStatsStrip/index.js +39 -0
- package/dist/lib/presentation/components/UserDetailLayout/index.d.ts +13 -0
- package/dist/lib/presentation/components/UserDetailLayout/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailLayout/index.js +101 -0
- package/dist/lib/presentation/components/UserDetailRouter/index.d.ts +16 -0
- package/dist/lib/presentation/components/UserDetailRouter/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/UserDetailRouter/index.js +33 -0
- package/dist/lib/presentation/components/WorkspaceMembershipCard/index.d.ts +15 -0
- package/dist/lib/presentation/components/WorkspaceMembershipCard/index.d.ts.map +1 -0
- package/dist/lib/presentation/components/WorkspaceMembershipCard/index.js +27 -0
- package/dist/lib/presentation/membersFilterFields/index.d.ts +10 -0
- package/dist/lib/presentation/membersFilterFields/index.d.ts.map +1 -0
- package/dist/lib/presentation/membersFilterFields/index.js +67 -0
- package/dist/lib/presentation/membersResultsAnchor/index.d.ts +17 -0
- package/dist/lib/presentation/membersResultsAnchor/index.d.ts.map +1 -0
- package/dist/lib/presentation/membersResultsAnchor/index.js +16 -0
- package/dist/lib/presentation/pages/InviteMemberPage/index.d.ts +7 -0
- package/dist/lib/presentation/pages/InviteMemberPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/InviteMemberPage/index.js +346 -0
- package/dist/lib/presentation/pages/MembersPage/index.d.ts +13 -0
- package/dist/lib/presentation/pages/MembersPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/MembersPage/index.js +140 -0
- package/dist/lib/presentation/pages/UserAccessPage/index.d.ts +18 -0
- package/dist/lib/presentation/pages/UserAccessPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserAccessPage/index.js +153 -0
- package/dist/lib/presentation/pages/UserActivityPage/index.d.ts +8 -0
- package/dist/lib/presentation/pages/UserActivityPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserActivityPage/index.js +228 -0
- package/dist/lib/presentation/pages/UserGeneralPage/index.d.ts +7 -0
- package/dist/lib/presentation/pages/UserGeneralPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserGeneralPage/index.js +72 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/ThemePreview.d.ts +11 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/ThemePreview.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/ThemePreview.js +24 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/index.d.ts +10 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserPreferencesPage/index.js +148 -0
- package/dist/lib/presentation/pages/UserRolesPage/index.d.ts +8 -0
- package/dist/lib/presentation/pages/UserRolesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserRolesPage/index.js +110 -0
- package/dist/lib/presentation/pages/UserSessionsPage/index.d.ts +7 -0
- package/dist/lib/presentation/pages/UserSessionsPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserSessionsPage/index.js +121 -0
- package/dist/lib/presentation/pages/UserWorkspacesPage/index.d.ts +8 -0
- package/dist/lib/presentation/pages/UserWorkspacesPage/index.d.ts.map +1 -0
- package/dist/lib/presentation/pages/UserWorkspacesPage/index.js +111 -0
- package/dist/lib/presentation/userDetailContext/index.d.ts +13 -0
- package/dist/lib/presentation/userDetailContext/index.d.ts.map +1 -0
- package/dist/lib/presentation/userDetailContext/index.js +5 -0
- package/dist/lib/presentation/usersPlugin/index.d.ts +27 -0
- package/dist/lib/presentation/usersPlugin/index.d.ts.map +1 -0
- package/dist/lib/presentation/usersPlugin/index.js +109 -0
- package/dist/lib/types/member/index.d.ts +63 -0
- package/dist/lib/types/member/index.d.ts.map +1 -0
- package/dist/lib/utils/membersFilterFields/index.d.ts +10 -0
- package/dist/lib/utils/membersFilterFields/index.d.ts.map +1 -0
- package/dist/lib/utils/membersKeys/index.d.ts +27 -0
- package/dist/lib/utils/membersKeys/index.d.ts.map +1 -0
- package/dist/lib/utils/toMember/index.d.ts +33 -0
- package/dist/lib/utils/toMember/index.d.ts.map +1 -0
- package/dist/lib/utils/userDetailContext/index.d.ts +13 -0
- package/dist/lib/utils/userDetailContext/index.d.ts.map +1 -0
- package/dist/lib/utils/usersPlugin/index.d.ts +27 -0
- package/dist/lib/utils/usersPlugin/index.d.ts.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A pragmatic email shape: a non-empty local part, an `@`, and a dotted domain
|
|
3
|
+
* with no spaces. Mirrors the server's invite-email rule closely enough for
|
|
4
|
+
* instant client feedback — the server remains the authority, so this is a
|
|
5
|
+
* format gate, not the final word.
|
|
6
|
+
*/
|
|
7
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
8
|
+
/** Longest email the server accepts (mirrors the server's column limit). */
|
|
9
|
+
const MAX_LENGTH = 320;
|
|
10
|
+
/**
|
|
11
|
+
* A member's email address — a client-side value object mirroring the server's
|
|
12
|
+
* invite-email rule. It exists so the invite form's email field and its submit
|
|
13
|
+
* guard validate one rule rather than each re-testing an inline `z.email()` /
|
|
14
|
+
* regex literal. Format only — whether the address is already taken is a server
|
|
15
|
+
* concern surfaced as a `409` on submit.
|
|
16
|
+
*/
|
|
17
|
+
export class Email {
|
|
18
|
+
email;
|
|
19
|
+
constructor(email) {
|
|
20
|
+
this.email = email;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Whether `value` is a well-shaped email, without throwing — the check the
|
|
24
|
+
* invite form's field uses for instant, per-keystroke feedback.
|
|
25
|
+
*/
|
|
26
|
+
static isValid(value) {
|
|
27
|
+
return (value.length > 0 &&
|
|
28
|
+
value.length <= MAX_LENGTH &&
|
|
29
|
+
EMAIL_PATTERN.test(value));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Builds an {@link Email}, throwing on an empty, over-long, or wrongly-shaped
|
|
33
|
+
* value. Used by the invite use-case as a last guard before the request.
|
|
34
|
+
*/
|
|
35
|
+
static create(value) {
|
|
36
|
+
if (!Email.isValid(value)) {
|
|
37
|
+
throw new Error(`Invalid member email: "${value}"`);
|
|
38
|
+
}
|
|
39
|
+
return new Email(value);
|
|
40
|
+
}
|
|
41
|
+
/** The underlying email string. */
|
|
42
|
+
get value() {
|
|
43
|
+
return this.email;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MemberGateway } from '../memberGateway';
|
|
2
|
+
/**
|
|
3
|
+
* HTTP implementation of {@link MemberGateway} over the shared `apiClient`
|
|
4
|
+
* (axios, same-origin, cookie-authed; paths omit the `/api` dev-proxy prefix).
|
|
5
|
+
* Every member response is run through the `toMember` anti-corruption mapper,
|
|
6
|
+
* sessions and workspace options through their inline mappers, and every failure
|
|
7
|
+
* is normalized with `toApiError`, so callers see the admin's models and
|
|
8
|
+
* `ApiError`, never axios internals. The single place `apiClient` is used in
|
|
9
|
+
* this plugin.
|
|
10
|
+
*/
|
|
11
|
+
export declare const httpMemberGateway: MemberGateway;
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/infrastructure/httpMemberGateway/index.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAGR,aAAa,EAKhB,MAAM,kBAAkB,CAAC;AAqD1B;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,aAuJ/B,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { apiClient, asAvatarColor, initialsOf, toApiError } from '@orthacms/utils-admin';
|
|
2
|
+
import { toInvitedMember, toMember, toMemberWithResetToken } from '../memberMapper';
|
|
3
|
+
/** Maps a session from the wire to the admin's model (timestamps → `Date`). */
|
|
4
|
+
function toUserSession(dto) {
|
|
5
|
+
return {
|
|
6
|
+
id: dto.id,
|
|
7
|
+
userAgent: dto.userAgent,
|
|
8
|
+
ipAddress: dto.ipAddress,
|
|
9
|
+
createdAt: new Date(dto.createdAt),
|
|
10
|
+
lastSeenAt: new Date(dto.lastUsedAt),
|
|
11
|
+
expiresAt: new Date(dto.expiresAt),
|
|
12
|
+
current: dto.current
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Maps a workspace row to the admin's option shape (initials + avatar color). */
|
|
16
|
+
function toWorkspaceOption(dto) {
|
|
17
|
+
return {
|
|
18
|
+
id: dto.id,
|
|
19
|
+
name: dto.name,
|
|
20
|
+
description: dto.description,
|
|
21
|
+
initials: initialsOf(dto.name),
|
|
22
|
+
color: asAvatarColor(dto.color)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* HTTP implementation of {@link MemberGateway} over the shared `apiClient`
|
|
27
|
+
* (axios, same-origin, cookie-authed; paths omit the `/api` dev-proxy prefix).
|
|
28
|
+
* Every member response is run through the `toMember` anti-corruption mapper,
|
|
29
|
+
* sessions and workspace options through their inline mappers, and every failure
|
|
30
|
+
* is normalized with `toApiError`, so callers see the admin's models and
|
|
31
|
+
* `ApiError`, never axios internals. The single place `apiClient` is used in
|
|
32
|
+
* this plugin.
|
|
33
|
+
*/
|
|
34
|
+
export const httpMemberGateway = {
|
|
35
|
+
async list(params) {
|
|
36
|
+
try {
|
|
37
|
+
const { data } = await apiClient.get('/users', {
|
|
38
|
+
params
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
items: data.items.map(toMember),
|
|
42
|
+
total: data.total,
|
|
43
|
+
page: data.page,
|
|
44
|
+
pageSize: data.pageSize
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw toApiError(error);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
async get(id) {
|
|
52
|
+
try {
|
|
53
|
+
const { data } = await apiClient.get(`/users/${id}`);
|
|
54
|
+
return toMember(data);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
throw toApiError(error);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
async invite(input) {
|
|
61
|
+
try {
|
|
62
|
+
const { data } = await apiClient.post('/users/invites', input);
|
|
63
|
+
return toInvitedMember(data);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw toApiError(error);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
async resendInvite(id) {
|
|
70
|
+
try {
|
|
71
|
+
const { data } = await apiClient.post(`/users/${id}/invites/resend`);
|
|
72
|
+
return toInvitedMember(data);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw toApiError(error);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
async issuePasswordReset(id) {
|
|
79
|
+
try {
|
|
80
|
+
const { data } = await apiClient.post(`/users/${id}/password-reset`);
|
|
81
|
+
return toMemberWithResetToken(data);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw toApiError(error);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
async revokeInvite(id) {
|
|
88
|
+
try {
|
|
89
|
+
await apiClient.delete(`/users/${id}/invites`);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw toApiError(error);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
async update({ id, ...body }) {
|
|
96
|
+
try {
|
|
97
|
+
const { data } = await apiClient.patch(`/users/${id}`, body);
|
|
98
|
+
return toMember(data);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw toApiError(error);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
async setStatus({ id, disabled }) {
|
|
105
|
+
const action = disabled ? 'disable' : 'enable';
|
|
106
|
+
try {
|
|
107
|
+
const { data } = await apiClient.post(`/users/${id}/${action}`);
|
|
108
|
+
return toMember(data);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
throw toApiError(error);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
async addWorkspace({ userId, workspaceId }) {
|
|
115
|
+
try {
|
|
116
|
+
await apiClient.post(`/workspaces/${workspaceId}/members`, {
|
|
117
|
+
userId
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw toApiError(error);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
async removeWorkspace({ userId, workspaceId }) {
|
|
125
|
+
try {
|
|
126
|
+
await apiClient.delete(`/workspaces/${workspaceId}/members/${userId}`);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
throw toApiError(error);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
async listSessions(id) {
|
|
133
|
+
try {
|
|
134
|
+
const { data } = await apiClient.get(`/users/${id}/sessions`);
|
|
135
|
+
return data.map(toUserSession);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
throw toApiError(error);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
async revokeSession({ userId, sessionId }) {
|
|
142
|
+
try {
|
|
143
|
+
await apiClient.delete(`/users/${userId}/sessions/${sessionId}`);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
throw toApiError(error);
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
async listWorkspaceOptions() {
|
|
150
|
+
try {
|
|
151
|
+
const { data } = await apiClient.get('/workspaces');
|
|
152
|
+
return data.map(toWorkspaceOption);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
throw toApiError(error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the invite link an admin hands to an invitee, from the raw token the
|
|
3
|
+
* API returned once.
|
|
4
|
+
*
|
|
5
|
+
* The origin comes from the browser rather than server config on purpose: the
|
|
6
|
+
* admin is *already* looking at the app on the URL the invitee should use, so
|
|
7
|
+
* `window.location.origin` is right by construction — no `publicBaseUrl` to
|
|
8
|
+
* misconfigure, and no host header to poison. When the mailer lands (identity
|
|
9
|
+
* epic #11) the server will need its own configured base URL; this stays the
|
|
10
|
+
* copy-it-yourself path.
|
|
11
|
+
*/
|
|
12
|
+
export declare function inviteLinkFor(token: string): string;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/infrastructure/inviteLink/index.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAInD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The admin route that redeems an invite. Owned by `@orthacms/identity-admin`
|
|
3
|
+
* (its router mounts `accept-invite` under `/identity`); repeated here because
|
|
4
|
+
* a path string is not worth a package dependency, and the e2e suites assert
|
|
5
|
+
* the built link so a drift would fail loudly.
|
|
6
|
+
*/
|
|
7
|
+
const ACCEPT_INVITE_PATH = '/identity/accept-invite';
|
|
8
|
+
/**
|
|
9
|
+
* Builds the invite link an admin hands to an invitee, from the raw token the
|
|
10
|
+
* API returned once.
|
|
11
|
+
*
|
|
12
|
+
* The origin comes from the browser rather than server config on purpose: the
|
|
13
|
+
* admin is *already* looking at the app on the URL the invitee should use, so
|
|
14
|
+
* `window.location.origin` is right by construction — no `publicBaseUrl` to
|
|
15
|
+
* misconfigure, and no host header to poison. When the mailer lands (identity
|
|
16
|
+
* epic #11) the server will need its own configured base URL; this stays the
|
|
17
|
+
* copy-it-yourself path.
|
|
18
|
+
*/
|
|
19
|
+
export function inviteLinkFor(token) {
|
|
20
|
+
const url = new URL(ACCEPT_INVITE_PATH, window.location.origin);
|
|
21
|
+
url.searchParams.set('token', token);
|
|
22
|
+
return url.toString();
|
|
23
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { InvitedMember, Member, MemberList, MemberRole, MemberWithResetToken } from '../../domain/types/member';
|
|
2
|
+
import type { UserSession } from '../../domain/types/session';
|
|
3
|
+
import type { WorkspaceOption } from '../../domain/types/workspaceOption';
|
|
4
|
+
import type { MembersListParams } from '../membersKeys';
|
|
5
|
+
/** The shape the invite form submits. */
|
|
6
|
+
export type InviteMemberInput = {
|
|
7
|
+
/** The invitee's email; the join link is sent here. */
|
|
8
|
+
email: string;
|
|
9
|
+
/** The global role granted on acceptance. */
|
|
10
|
+
role: MemberRole;
|
|
11
|
+
/** Optional display name (the invitee can set their own on accept). */
|
|
12
|
+
name?: string;
|
|
13
|
+
/** Workspaces to grant the new member access to (optional). */
|
|
14
|
+
workspaceIds?: string[];
|
|
15
|
+
};
|
|
16
|
+
/** A partial member edit; omitted fields are left unchanged. */
|
|
17
|
+
export type UpdateMemberInput = {
|
|
18
|
+
/** The member to edit. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** New display name. */
|
|
21
|
+
name?: string;
|
|
22
|
+
/** New global role. */
|
|
23
|
+
role?: MemberRole;
|
|
24
|
+
};
|
|
25
|
+
/** Which member to flip, and which way. */
|
|
26
|
+
export type SetMemberStatusInput = {
|
|
27
|
+
/** The member to update. */
|
|
28
|
+
id: string;
|
|
29
|
+
/** `true` disables the account, `false` re-enables it. */
|
|
30
|
+
disabled: boolean;
|
|
31
|
+
};
|
|
32
|
+
/** Identifies the membership to create: which member, which workspace. */
|
|
33
|
+
export type AddWorkspaceMemberInput = {
|
|
34
|
+
/** The member being added. */
|
|
35
|
+
userId: string;
|
|
36
|
+
/** The workspace to add them to. */
|
|
37
|
+
workspaceId: string;
|
|
38
|
+
};
|
|
39
|
+
/** Identifies the membership to remove: which member, which workspace. */
|
|
40
|
+
export type RemoveWorkspaceMemberInput = {
|
|
41
|
+
/** The member being removed. */
|
|
42
|
+
userId: string;
|
|
43
|
+
/** The workspace to remove them from. */
|
|
44
|
+
workspaceId: string;
|
|
45
|
+
};
|
|
46
|
+
/** Identifies the session to revoke: whose, and which. */
|
|
47
|
+
export type RevokeSessionInput = {
|
|
48
|
+
/** The member who owns the session. */
|
|
49
|
+
userId: string;
|
|
50
|
+
/** The session row id to revoke. */
|
|
51
|
+
sessionId: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* The port over the remote users/members API — the single seam the admin plugin
|
|
55
|
+
* talks to instead of `apiClient` directly. Every method returns the admin's
|
|
56
|
+
* mapped models (via the `memberMapper` anti-corruption layer, or an inline
|
|
57
|
+
* timestamp/avatar mapping for sessions and workspace options), never the wire
|
|
58
|
+
* shape, and normalizes every failure to `ApiError`, so the application hooks
|
|
59
|
+
* and presentation stay off the transport. {@link httpMemberGateway} is the HTTP
|
|
60
|
+
* implementation.
|
|
61
|
+
*/
|
|
62
|
+
export type MemberGateway = {
|
|
63
|
+
/** Lists one page of members via `GET /api/users`. */
|
|
64
|
+
list(params: MembersListParams): Promise<MemberList>;
|
|
65
|
+
/** Fetches one member's full record via `GET /api/users/:id`. */
|
|
66
|
+
get(id: string): Promise<Member>;
|
|
67
|
+
/**
|
|
68
|
+
* Invites a person via `POST /api/users/invites` (`409` = email taken).
|
|
69
|
+
* Resolves with the new member **and** their one-time invite token — the
|
|
70
|
+
* only moment it is readable, since no mailer sends the link yet.
|
|
71
|
+
*/
|
|
72
|
+
invite(input: InviteMemberInput): Promise<InvitedMember>;
|
|
73
|
+
/**
|
|
74
|
+
* Rotates a pending invite via `POST /api/users/:id/invites/resend`,
|
|
75
|
+
* resolving with the member and the fresh token. Rotating kills the
|
|
76
|
+
* previous link, so the new one has to reach the invitee.
|
|
77
|
+
*/
|
|
78
|
+
resendInvite(id: string): Promise<InvitedMember>;
|
|
79
|
+
/** Revokes a pending invite via `DELETE /api/users/:id/invites`. */
|
|
80
|
+
revokeInvite(id: string): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Mints a one-time password-reset link for an active member via
|
|
83
|
+
* `POST /api/users/:id/password-reset`, resolving with the member and the
|
|
84
|
+
* raw token (`409` = the member is not active, or one was just issued).
|
|
85
|
+
* Issuing kills any previous link, so the new one has to reach the member.
|
|
86
|
+
*/
|
|
87
|
+
issuePasswordReset(id: string): Promise<MemberWithResetToken>;
|
|
88
|
+
/** Edits name/role via `PATCH /api/users/:id` (`409` = last admin). */
|
|
89
|
+
update(input: UpdateMemberInput): Promise<Member>;
|
|
90
|
+
/** Disables or re-enables a member via `POST /api/users/:id/(disable|enable)`. */
|
|
91
|
+
setStatus(input: SetMemberStatusInput): Promise<Member>;
|
|
92
|
+
/** Links a member to a workspace via `POST /api/workspaces/:id/members`. */
|
|
93
|
+
addWorkspace(input: AddWorkspaceMemberInput): Promise<void>;
|
|
94
|
+
/** Unlinks a member via `DELETE /api/workspaces/:id/members/:userId`. */
|
|
95
|
+
removeWorkspace(input: RemoveWorkspaceMemberInput): Promise<void>;
|
|
96
|
+
/** Lists a member's live sessions via `GET /api/users/:id/sessions`. */
|
|
97
|
+
listSessions(id: string): Promise<UserSession[]>;
|
|
98
|
+
/** Revokes one session via `DELETE /api/users/:id/sessions/:sessionId`. */
|
|
99
|
+
revokeSession(input: RevokeSessionInput): Promise<void>;
|
|
100
|
+
/** Lists every workspace (via `GET /api/workspaces`) for the assignment steps. */
|
|
101
|
+
listWorkspaceOptions(): Promise<WorkspaceOption[]>;
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/infrastructure/memberGateway/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,aAAa,EACb,MAAM,EACN,UAAU,EACV,UAAU,EACV,oBAAoB,EACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,yCAAyC;AACzC,MAAM,MAAM,iBAAiB,GAAG;IAC5B,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,IAAI,EAAE,UAAU,CAAC;IACjB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,iBAAiB,GAAG;IAC5B,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,IAAI,CAAC,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,2CAA2C;AAC3C,MAAM,MAAM,oBAAoB,GAAG;IAC/B,4BAA4B;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,uBAAuB,GAAG;IAClC,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,0BAA0B,GAAG;IACrC,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,kBAAkB,GAAG;IAC7B,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG;IACxB,sDAAsD;IACtD,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACrD,iEAAiE;IACjE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACzD;;;;OAIG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACjD,oEAAoE;IACpE,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,uEAAuE;IACvE,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,kFAAkF;IAClF,SAAS,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD,4EAA4E;IAC5E,YAAY,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,yEAAyE;IACzE,eAAe,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,wEAAwE;IACxE,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACjD,2EAA2E;IAC3E,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,kFAAkF;IAClF,oBAAoB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CACtD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { InvitedMember, Member, MemberStatus, MemberWithResetToken } from '../../domain/types/member';
|
|
2
|
+
/** A member's role as returned by the API. */
|
|
3
|
+
export type MemberRoleResponse = {
|
|
4
|
+
id: string;
|
|
5
|
+
key: string;
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
/** A member's workspace as returned by the API. */
|
|
9
|
+
export type MemberWorkspaceResponse = {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description: string | null;
|
|
13
|
+
color: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A member as returned by the users API. `name` is `null` until the invite is
|
|
17
|
+
* accepted; `createdAt` is an ISO timestamp (the invite date while
|
|
18
|
+
* `pending`); `isLastAdmin` is the server-computed "sole active admin" flag
|
|
19
|
+
* the guardrail UI reads.
|
|
20
|
+
*/
|
|
21
|
+
export type MemberResponse = {
|
|
22
|
+
id: string;
|
|
23
|
+
email: string;
|
|
24
|
+
name: string | null;
|
|
25
|
+
role: MemberRoleResponse;
|
|
26
|
+
status: MemberStatus;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
isLastAdmin: boolean;
|
|
29
|
+
workspaces: MemberWorkspaceResponse[];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* A member as returned by the two endpoints that mint an invite token
|
|
33
|
+
* (`POST /users/invites` and `POST /users/:id/invites/resend`). Identical to
|
|
34
|
+
* {@link MemberResponse} plus the raw token — the only responses that carry one.
|
|
35
|
+
*/
|
|
36
|
+
export type InvitedMemberResponse = MemberResponse & {
|
|
37
|
+
inviteToken: string;
|
|
38
|
+
};
|
|
39
|
+
/** Maps a member from the wire to the admin's `Member` model. */
|
|
40
|
+
export declare function toMember(dto: MemberResponse): Member;
|
|
41
|
+
/**
|
|
42
|
+
* Maps an invite/resend response to the admin's {@link InvitedMember} — the
|
|
43
|
+
* mapped member plus the one-time token, carried through verbatim.
|
|
44
|
+
*/
|
|
45
|
+
export declare function toInvitedMember(dto: InvitedMemberResponse): InvitedMember;
|
|
46
|
+
/**
|
|
47
|
+
* A member as returned by the one endpoint that mints a password-reset token
|
|
48
|
+
* (`POST /users/:id/password-reset`). Identical to {@link MemberResponse} plus
|
|
49
|
+
* the raw token — the only response that carries one.
|
|
50
|
+
*/
|
|
51
|
+
export type PasswordResetMemberResponse = MemberResponse & {
|
|
52
|
+
resetToken: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Maps a password-reset response to the admin's {@link MemberWithResetToken} —
|
|
56
|
+
* the mapped member plus the one-time token, carried through verbatim.
|
|
57
|
+
*/
|
|
58
|
+
export declare function toMemberWithResetToken(dto: PasswordResetMemberResponse): MemberWithResetToken;
|
|
59
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/infrastructure/memberMapper/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACR,aAAa,EACb,MAAM,EAEN,YAAY,EACZ,oBAAoB,EAEvB,MAAM,2BAA2B,CAAC;AAQnC,8CAA8C;AAC9C,MAAM,MAAM,kBAAkB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,uBAAuB,EAAE,CAAC;CACzC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG;IACjD,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAaF,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAqBpD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,qBAAqB,GAAG,aAAa,CAEzE;AAED;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,cAAc,GAAG;IACvD,UAAU,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,sBAAsB,CAClC,GAAG,EAAE,2BAA2B,GACjC,oBAAoB,CAEtB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { asAvatarColor, avatarColorForId, initialsOf } from '@orthacms/utils-admin';
|
|
2
|
+
/** Maps a workspace from the wire to the admin's presentational shape. */
|
|
3
|
+
function toMemberWorkspace(dto) {
|
|
4
|
+
return {
|
|
5
|
+
id: dto.id,
|
|
6
|
+
name: dto.name,
|
|
7
|
+
description: dto.description,
|
|
8
|
+
initials: initialsOf(dto.name),
|
|
9
|
+
color: asAvatarColor(dto.color)
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** Maps a member from the wire to the admin's `Member` model. */
|
|
13
|
+
export function toMember(dto) {
|
|
14
|
+
const name = dto.name ?? dto.email;
|
|
15
|
+
return {
|
|
16
|
+
id: dto.id,
|
|
17
|
+
name,
|
|
18
|
+
email: dto.email,
|
|
19
|
+
initials: initialsOf(name),
|
|
20
|
+
color: avatarColorForId(dto.id),
|
|
21
|
+
// An unknown role key (a custom, non-system role — the server's
|
|
22
|
+
// `Role.create` accepts any non-empty key) maps to `null`, NOT to a
|
|
23
|
+
// guessed `viewer`. Coercing it would make the roster and the Role tab
|
|
24
|
+
// positively assert a privilege level the member does not hold; `null`
|
|
25
|
+
// means "not one of the three assignable roles", and the UI falls back
|
|
26
|
+
// to the server's own `roleName` and refuses to offer a change.
|
|
27
|
+
role: isMemberRole(dto.role.key) ? dto.role.key : null,
|
|
28
|
+
roleName: dto.role.name,
|
|
29
|
+
status: dto.status,
|
|
30
|
+
joinedAt: new Date(dto.createdAt),
|
|
31
|
+
isLastAdmin: dto.isLastAdmin,
|
|
32
|
+
workspaces: dto.workspaces.map(toMemberWorkspace)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Maps an invite/resend response to the admin's {@link InvitedMember} — the
|
|
37
|
+
* mapped member plus the one-time token, carried through verbatim.
|
|
38
|
+
*/
|
|
39
|
+
export function toInvitedMember(dto) {
|
|
40
|
+
return { ...toMember(dto), inviteToken: dto.inviteToken };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Maps a password-reset response to the admin's {@link MemberWithResetToken} —
|
|
44
|
+
* the mapped member plus the one-time token, carried through verbatim.
|
|
45
|
+
*/
|
|
46
|
+
export function toMemberWithResetToken(dto) {
|
|
47
|
+
return { ...toMember(dto), resetToken: dto.resetToken };
|
|
48
|
+
}
|
|
49
|
+
/** Whether a wire role key is one of the admin's assignable roles. */
|
|
50
|
+
function isMemberRole(key) {
|
|
51
|
+
return key === 'admin' || key === 'contributor' || key === 'viewer';
|
|
52
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Parameters accepted by `GET /api/users` — the list query's filter/paging. */
|
|
2
|
+
export type MembersListParams = {
|
|
3
|
+
/** Case-insensitive name/email substring; omit for no filter. */
|
|
4
|
+
search?: string;
|
|
5
|
+
/** Query-builder filter tree as a JSON string; omit for no structured filter. */
|
|
6
|
+
filter?: string;
|
|
7
|
+
/** 1-based page number; the server defaults to 1. */
|
|
8
|
+
page?: number;
|
|
9
|
+
/** Rows per page; the server defaults to its own page size. */
|
|
10
|
+
pageSize?: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Query keys for the members cache. The list endpoint lives under
|
|
14
|
+
* `membersKeys.list(params)`; mutations invalidate `membersKeys.all` to
|
|
15
|
+
* refresh every cached page (an added/changed/removed row may land anywhere).
|
|
16
|
+
*
|
|
17
|
+
* **Sessions deliberately sit under their own root**, not under
|
|
18
|
+
* `['members','detail',id,…]`. TanStack matches by prefix, so nesting them
|
|
19
|
+
* would make every member mutation — a rename, a role change — invalidate
|
|
20
|
+
* every cached session list too, which no member mutation can affect. Keeping
|
|
21
|
+
* the root separate is what makes the broad `all` invalidation safe.
|
|
22
|
+
*/
|
|
23
|
+
export declare const membersKeys: {
|
|
24
|
+
/** Root key covering the member list and detail queries. */
|
|
25
|
+
all: readonly ["members"];
|
|
26
|
+
/** One list page for the given params. */
|
|
27
|
+
list: (params: MembersListParams) => readonly ["members", "list", MembersListParams];
|
|
28
|
+
/** One member's full detail record (the user detail page). */
|
|
29
|
+
detail: (id: string) => readonly ["members", "detail", string];
|
|
30
|
+
/**
|
|
31
|
+
* One member's live sessions (the detail page's Sessions tab). Rooted at
|
|
32
|
+
* `member-sessions` so `membersKeys.all` cannot reach it — see the note
|
|
33
|
+
* above.
|
|
34
|
+
*/
|
|
35
|
+
sessions: (id: string) => readonly ["member-sessions", string];
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/infrastructure/membersKeys/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG;IAC5B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW;IACpB,4DAA4D;;IAE5D,0CAA0C;mBAC3B,iBAAiB;IAChC,8DAA8D;iBACjD,MAAM;IACnB;;;;OAIG;mBACY,MAAM;CACxB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query keys for the members cache. The list endpoint lives under
|
|
3
|
+
* `membersKeys.list(params)`; mutations invalidate `membersKeys.all` to
|
|
4
|
+
* refresh every cached page (an added/changed/removed row may land anywhere).
|
|
5
|
+
*
|
|
6
|
+
* **Sessions deliberately sit under their own root**, not under
|
|
7
|
+
* `['members','detail',id,…]`. TanStack matches by prefix, so nesting them
|
|
8
|
+
* would make every member mutation — a rename, a role change — invalidate
|
|
9
|
+
* every cached session list too, which no member mutation can affect. Keeping
|
|
10
|
+
* the root separate is what makes the broad `all` invalidation safe.
|
|
11
|
+
*/
|
|
12
|
+
export const membersKeys = {
|
|
13
|
+
/** Root key covering the member list and detail queries. */
|
|
14
|
+
all: ['members'],
|
|
15
|
+
/** One list page for the given params. */
|
|
16
|
+
list: (params) => ['members', 'list', params],
|
|
17
|
+
/** One member's full detail record (the user detail page). */
|
|
18
|
+
detail: (id) => ['members', 'detail', id],
|
|
19
|
+
/**
|
|
20
|
+
* One member's live sessions (the detail page's Sessions tab). Rooted at
|
|
21
|
+
* `member-sessions` so `membersKeys.all` cannot reach it — see the note
|
|
22
|
+
* above.
|
|
23
|
+
*/
|
|
24
|
+
sessions: (id) => ['member-sessions', id]
|
|
25
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the reset link an admin hands to a member, from the raw token the API
|
|
3
|
+
* returned once.
|
|
4
|
+
*
|
|
5
|
+
* The origin comes from the browser rather than server config on purpose: the
|
|
6
|
+
* admin is *already* looking at the app on the URL the member should use, so
|
|
7
|
+
* `window.location.origin` is right by construction — no `publicBaseUrl` to
|
|
8
|
+
* misconfigure, and no host header to poison. When the mailer lands (identity
|
|
9
|
+
* epic #11) the server will need its own configured base URL; this stays the
|
|
10
|
+
* copy-it-yourself path.
|
|
11
|
+
*/
|
|
12
|
+
export declare function passwordResetLinkFor(token: string): string;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/infrastructure/passwordResetLink/index.ts"],"names":[],"mappings":"AASA;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI1D"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The admin route that redeems a password reset. Owned by
|
|
3
|
+
* `@orthacms/identity-admin` (its router mounts `reset-password` under
|
|
4
|
+
* `/identity`); repeated here for the same reason the invite path is — a path
|
|
5
|
+
* string is not worth a package dependency, and the e2e suites assert the built
|
|
6
|
+
* link so a drift would fail loudly.
|
|
7
|
+
*/
|
|
8
|
+
const RESET_PASSWORD_PATH = '/identity/reset-password';
|
|
9
|
+
/**
|
|
10
|
+
* Builds the reset link an admin hands to a member, from the raw token the API
|
|
11
|
+
* returned once.
|
|
12
|
+
*
|
|
13
|
+
* The origin comes from the browser rather than server config on purpose: the
|
|
14
|
+
* admin is *already* looking at the app on the URL the member should use, so
|
|
15
|
+
* `window.location.origin` is right by construction — no `publicBaseUrl` to
|
|
16
|
+
* misconfigure, and no host header to poison. When the mailer lands (identity
|
|
17
|
+
* epic #11) the server will need its own configured base URL; this stays the
|
|
18
|
+
* copy-it-yourself path.
|
|
19
|
+
*/
|
|
20
|
+
export function passwordResetLinkFor(token) {
|
|
21
|
+
const url = new URL(RESET_PASSWORD_PATH, window.location.origin);
|
|
22
|
+
url.searchParams.set('token', token);
|
|
23
|
+
return url.toString();
|
|
24
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ThemePreference } from '@orthacms/design-system';
|
|
2
|
+
/**
|
|
3
|
+
* The current user's own preferences, as carried over `/api/preferences`.
|
|
4
|
+
* Today that is just the colour theme; the object shape leaves room for more
|
|
5
|
+
* self-service preferences without changing the endpoint contract.
|
|
6
|
+
*/
|
|
7
|
+
export type UserPreferences = {
|
|
8
|
+
/** The user's chosen colour theme. */
|
|
9
|
+
theme: ThemePreference;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* React Query keys for a user's own preferences. Distinct from `membersKeys` —
|
|
13
|
+
* these are the caller's *own* app preferences, not a member record, so they
|
|
14
|
+
* never invalidate alongside the members list.
|
|
15
|
+
*
|
|
16
|
+
* The key is scoped **by user id**, not a flat `'me'`. Sign-out only invalidates
|
|
17
|
+
* the current-user query; every other cache entry survives it. With a shared
|
|
18
|
+
* `'me'` key, signing in as someone else on the same machine would read the
|
|
19
|
+
* previous user's cached theme (and, because this query never goes stale, never
|
|
20
|
+
* refetch to correct it). Scoping by id makes that structurally impossible.
|
|
21
|
+
*/
|
|
22
|
+
export declare const preferencesKeys: {
|
|
23
|
+
/** One user's preferences. */
|
|
24
|
+
forUser: (userId: string) => readonly ["preferences", string];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The one place `/api/preferences` is spoken to. Keeps `apiClient` out of the
|
|
28
|
+
* application hooks (per this plugin's layering) and normalizes transport
|
|
29
|
+
* errors to `ApiError` so callers branch on status, not axios internals.
|
|
30
|
+
*/
|
|
31
|
+
export declare const httpPreferencesGateway: {
|
|
32
|
+
/** Reads the signed-in user's preferences (defaults if never saved). */
|
|
33
|
+
get(): Promise<UserPreferences>;
|
|
34
|
+
/** Persists the signed-in user's theme choice, returning the stored row. */
|
|
35
|
+
updateTheme(theme: ThemePreference): Promise<UserPreferences>;
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/infrastructure/preferencesGateway/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAC1B,sCAAsC;IACtC,KAAK,EAAE,eAAe,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe;IACxB,8BAA8B;sBACZ,MAAM;CAC3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;IAC/B,wEAAwE;WAC3D,OAAO,CAAC,eAAe,CAAC;IAUrC,4EAA4E;uBACnD,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;CAWtE,CAAC"}
|