@oxyhq/services 6.10.7 → 7.0.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/commonjs/index.js +211 -49
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/client.js +25 -4
- package/lib/commonjs/ui/client.js.map +1 -1
- package/lib/commonjs/ui/components/AccountMenu.js +485 -0
- package/lib/commonjs/ui/components/AccountMenu.js.map +1 -0
- package/lib/commonjs/ui/components/AccountMenuButton.js +120 -0
- package/lib/commonjs/ui/components/AccountMenuButton.js.map +1 -0
- package/lib/commonjs/ui/components/ActingAsBanner.js +2 -2
- package/lib/commonjs/ui/components/ActingAsBanner.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileCard.js +2 -2
- package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
- package/lib/commonjs/ui/components/StepBasedScreen.js +2 -2
- package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/commonjs/ui/components/accountMenuRows.js +45 -0
- package/lib/commonjs/ui/components/accountMenuRows.js.map +1 -0
- package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +5 -5
- package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
- package/lib/commonjs/ui/components/payment/PaymentMethodStep.js +3 -2
- package/lib/commonjs/ui/components/payment/PaymentMethodStep.js.map +1 -1
- package/lib/commonjs/ui/components/theming.js +2 -2
- package/lib/commonjs/ui/components/theming.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +211 -21
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +36 -2
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/mutationKeys.js +6 -0
- package/lib/commonjs/ui/hooks/mutations/mutationKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +138 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +67 -2
- package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +27 -2
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +13 -2
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +30 -0
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/commonjs/ui/index.js +132 -85
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/navigation/routes.js +6 -7
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js +3 -2
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +202 -0
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js +3 -2
- package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +3 -2
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FAQScreen.js +7 -4
- package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +21 -16
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HelpSupportScreen.js +3 -2
- package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js +7 -4
- package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +3 -2
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +6 -4
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +780 -0
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/NotificationsScreen.js +175 -0
- package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +18 -12
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PreferencesScreen.js +220 -0
- package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +14 -10
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +3 -3
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +8 -5
- package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js +6 -4
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserLinksScreen.js +3 -2
- package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserListScreen.js +2 -2
- package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +3 -2
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +3 -2
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +2 -2
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +4 -3
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +3 -2
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/utils/activeAuthuser.js +85 -0
- package/lib/commonjs/ui/utils/activeAuthuser.js.map +1 -0
- package/lib/module/index.js +58 -16
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/client.js +5 -3
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/AccountMenu.js +480 -0
- package/lib/module/ui/components/AccountMenu.js.map +1 -0
- package/lib/module/ui/components/AccountMenuButton.js +115 -0
- package/lib/module/ui/components/AccountMenuButton.js.map +1 -0
- package/lib/module/ui/components/ActingAsBanner.js +2 -2
- package/lib/module/ui/components/ActingAsBanner.js.map +1 -1
- package/lib/module/ui/components/ProfileCard.js +1 -1
- package/lib/module/ui/components/ProfileCard.js.map +1 -1
- package/lib/module/ui/components/StepBasedScreen.js +1 -1
- package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/module/ui/components/accountMenuRows.js +41 -0
- package/lib/module/ui/components/accountMenuRows.js.map +1 -0
- package/lib/module/ui/components/payment/PaymentDetailsStep.js +1 -1
- package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
- package/lib/module/ui/components/payment/PaymentMethodStep.js +1 -1
- package/lib/module/ui/components/payment/PaymentMethodStep.js.map +1 -1
- package/lib/module/ui/components/theming.js +1 -1
- package/lib/module/ui/components/theming.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +211 -21
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +36 -2
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/hooks/mutations/mutationKeys.js +6 -0
- package/lib/module/ui/hooks/mutations/mutationKeys.js.map +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +135 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +60 -1
- package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js +24 -0
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/useAuth.js +13 -2
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +30 -0
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/module/ui/index.js +34 -78
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/navigation/routes.js +6 -7
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/module/ui/screens/ConnectedAppsScreen.js +198 -0
- package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -0
- package/lib/module/ui/screens/CreateManagedAccountScreen.js +1 -1
- package/lib/module/ui/screens/CreateManagedAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/FAQScreen.js +3 -1
- package/lib/module/ui/screens/FAQScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +6 -2
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/HelpSupportScreen.js +1 -1
- package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js +3 -1
- package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js +2 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +775 -0
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -0
- package/lib/module/ui/screens/NotificationsScreen.js +169 -0
- package/lib/module/ui/screens/NotificationsScreen.js.map +1 -0
- package/lib/module/ui/screens/PaymentGatewayScreen.js +9 -3
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/PreferencesScreen.js +214 -0
- package/lib/module/ui/screens/PreferencesScreen.js.map +1 -0
- package/lib/module/ui/screens/PrivacySettingsScreen.js +4 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +2 -2
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SavesCollectionsScreen.js +3 -1
- package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
- package/lib/module/ui/screens/SearchSettingsScreen.js +2 -1
- package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/UserLinksScreen.js +1 -1
- package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
- package/lib/module/ui/screens/UserListScreen.js +1 -1
- package/lib/module/ui/screens/UserListScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/module/ui/utils/activeAuthuser.js +79 -0
- package/lib/module/ui/utils/activeAuthuser.js.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +23 -6
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/client.d.ts +7 -2
- package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +23 -0
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts +19 -0
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts +27 -0
- package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/mutationKeys.d.ts +5 -0
- package/lib/typescript/commonjs/ui/hooks/mutations/mutationKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +26 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts +32 -3
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts +10 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useSecurityQueries.d.ts +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useSecurityQueries.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts +8 -2
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +32 -18
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/{module/ui/screens/AccountOverviewScreen.d.ts → commonjs/ui/screens/ConnectedAppsScreen.d.ts} +1 -1
- package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/FAQScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +13 -0
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/{AccountOverviewScreen.d.ts → NotificationsScreen.d.ts} +1 -1
- package/lib/typescript/commonjs/ui/screens/NotificationsScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/PaymentGatewayScreen.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/{AccountSettingsScreen.d.ts → PreferencesScreen.d.ts} +2 -5
- package/lib/typescript/commonjs/ui/screens/PreferencesScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts +42 -0
- package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +23 -6
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +7 -2
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AccountMenu.d.ts +23 -0
- package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts +19 -0
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts +27 -0
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/mutationKeys.d.ts +5 -0
- package/lib/typescript/module/ui/hooks/mutations/mutationKeys.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +26 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts +32 -3
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts +10 -1
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useSecurityQueries.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/queries/useSecurityQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts +8 -2
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +32 -18
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/{AccountSettingsScreen.d.ts → ConnectedAppsScreen.d.ts} +2 -5
- package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/FAQScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +13 -0
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts +5 -0
- package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts +5 -0
- package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/activeAuthuser.d.ts +42 -0
- package/lib/typescript/module/ui/utils/activeAuthuser.d.ts.map +1 -0
- package/package.json +20 -9
- package/src/index.ts +141 -47
- package/src/ui/client.ts +7 -2
- package/src/ui/components/AccountMenu.tsx +534 -0
- package/src/ui/components/AccountMenuButton.tsx +113 -0
- package/src/ui/components/ActingAsBanner.tsx +2 -2
- package/src/ui/components/ProfileCard.tsx +1 -1
- package/src/ui/components/StepBasedScreen.tsx +1 -1
- package/src/ui/components/accountMenuRows.ts +60 -0
- package/src/ui/components/payment/PaymentDetailsStep.tsx +1 -1
- package/src/ui/components/payment/PaymentMethodStep.tsx +1 -1
- package/src/ui/components/theming.tsx +1 -1
- package/src/ui/context/OxyContext.tsx +204 -18
- package/src/ui/context/hooks/useAuthOperations.ts +36 -2
- package/src/ui/hooks/mutations/mutationKeys.ts +11 -0
- package/src/ui/hooks/mutations/useAccountMutations.ts +154 -2
- package/src/ui/hooks/queries/queryKeys.ts +54 -4
- package/src/ui/hooks/queries/useAccountQueries.ts +25 -1
- package/src/ui/hooks/useAuth.ts +23 -4
- package/src/ui/hooks/useSessionManagement.ts +29 -0
- package/src/ui/index.ts +37 -98
- package/src/ui/navigation/routes.ts +9 -11
- package/src/ui/screens/AccountVerificationScreen.tsx +1 -1
- package/src/ui/screens/ConnectedAppsScreen.tsx +225 -0
- package/src/ui/screens/CreateManagedAccountScreen.tsx +1 -1
- package/src/ui/screens/EditProfileFieldScreen.tsx +1 -1
- package/src/ui/screens/FAQScreen.tsx +3 -1
- package/src/ui/screens/FeedbackScreen.tsx +6 -10
- package/src/ui/screens/HelpSupportScreen.tsx +1 -1
- package/src/ui/screens/HistoryViewScreen.tsx +3 -1
- package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
- package/src/ui/screens/LegalDocumentsScreen.tsx +2 -1
- package/src/ui/screens/ManageAccountScreen.tsx +1102 -0
- package/src/ui/screens/NotificationsScreen.tsx +189 -0
- package/src/ui/screens/PaymentGatewayScreen.tsx +10 -12
- package/src/ui/screens/PreferencesScreen.tsx +263 -0
- package/src/ui/screens/PrivacySettingsScreen.tsx +4 -1
- package/src/ui/screens/ProfileScreen.tsx +2 -2
- package/src/ui/screens/SavesCollectionsScreen.tsx +3 -1
- package/src/ui/screens/SearchSettingsScreen.tsx +2 -1
- package/src/ui/screens/UserLinksScreen.tsx +1 -1
- package/src/ui/screens/UserListScreen.tsx +1 -1
- package/src/ui/screens/karma/KarmaAboutScreen.tsx +1 -1
- package/src/ui/screens/karma/KarmaFAQScreen.tsx +1 -1
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +1 -1
- package/src/ui/screens/karma/KarmaRewardsScreen.tsx +1 -1
- package/src/ui/screens/karma/KarmaRulesScreen.tsx +1 -1
- package/src/ui/utils/activeAuthuser.ts +78 -0
- package/lib/commonjs/ui/components/feedback/index.js +0 -54
- package/lib/commonjs/ui/components/feedback/index.js.map +0 -1
- package/lib/commonjs/ui/components/icon/index.js +0 -21
- package/lib/commonjs/ui/components/icon/index.js.map +0 -1
- package/lib/commonjs/ui/components/index.js +0 -104
- package/lib/commonjs/ui/components/index.js.map +0 -1
- package/lib/commonjs/ui/components/modals/index.js +0 -14
- package/lib/commonjs/ui/components/modals/index.js.map +0 -1
- package/lib/commonjs/ui/components/payment/index.js +0 -80
- package/lib/commonjs/ui/components/payment/index.js.map +0 -1
- package/lib/commonjs/ui/hooks/index.js +0 -92
- package/lib/commonjs/ui/hooks/index.js.map +0 -1
- package/lib/commonjs/ui/hooks/mutations/index.js +0 -68
- package/lib/commonjs/ui/hooks/mutations/index.js.map +0 -1
- package/lib/commonjs/ui/hooks/queries/index.js +0 -155
- package/lib/commonjs/ui/hooks/queries/index.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +0 -344
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +0 -724
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +0 -643
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +0 -1029
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +0 -512
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +0 -1
- package/lib/commonjs/ui/styles/index.js +0 -39
- package/lib/commonjs/ui/styles/index.js.map +0 -1
- package/lib/module/ui/components/feedback/index.js +0 -8
- package/lib/module/ui/components/feedback/index.js.map +0 -1
- package/lib/module/ui/components/icon/index.js +0 -5
- package/lib/module/ui/components/icon/index.js.map +0 -1
- package/lib/module/ui/components/index.js +0 -18
- package/lib/module/ui/components/index.js.map +0 -1
- package/lib/module/ui/components/modals/index.js +0 -4
- package/lib/module/ui/components/modals/index.js.map +0 -1
- package/lib/module/ui/components/payment/index.js +0 -10
- package/lib/module/ui/components/payment/index.js.map +0 -1
- package/lib/module/ui/hooks/index.js +0 -11
- package/lib/module/ui/hooks/index.js.map +0 -1
- package/lib/module/ui/hooks/mutations/index.js +0 -15
- package/lib/module/ui/hooks/mutations/index.js.map +0 -1
- package/lib/module/ui/hooks/queries/index.js +0 -26
- package/lib/module/ui/hooks/queries/index.js.map +0 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +0 -339
- package/lib/module/ui/screens/AccountCenterScreen.js.map +0 -1
- package/lib/module/ui/screens/AccountOverviewScreen.js +0 -719
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +0 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +0 -638
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +0 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +0 -1024
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +0 -508
- package/lib/module/ui/screens/SessionManagementScreen.js.map +0 -1
- package/lib/module/ui/styles/index.js +0 -6
- package/lib/module/ui/styles/index.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/feedback/index.d.ts +0 -7
- package/lib/typescript/commonjs/ui/components/feedback/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/icon/index.d.ts +0 -4
- package/lib/typescript/commonjs/ui/components/icon/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/index.d.ts +0 -13
- package/lib/typescript/commonjs/ui/components/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/modals/index.d.ts +0 -2
- package/lib/typescript/commonjs/ui/components/modals/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/payment/index.d.ts +0 -9
- package/lib/typescript/commonjs/ui/components/payment/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/index.d.ts +0 -9
- package/lib/typescript/commonjs/ui/hooks/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/index.d.ts +0 -9
- package/lib/typescript/commonjs/ui/hooks/mutations/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/queries/index.d.ts +0 -13
- package/lib/typescript/commonjs/ui/hooks/queries/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/AccountCenterScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/AccountCenterScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/AccountOverviewScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/SessionManagementScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/SessionManagementScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/styles/index.d.ts +0 -4
- package/lib/typescript/commonjs/ui/styles/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/feedback/index.d.ts +0 -7
- package/lib/typescript/module/ui/components/feedback/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/icon/index.d.ts +0 -4
- package/lib/typescript/module/ui/components/icon/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/index.d.ts +0 -13
- package/lib/typescript/module/ui/components/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/modals/index.d.ts +0 -2
- package/lib/typescript/module/ui/components/modals/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/payment/index.d.ts +0 -9
- package/lib/typescript/module/ui/components/payment/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/index.d.ts +0 -9
- package/lib/typescript/module/ui/hooks/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/mutations/index.d.ts +0 -9
- package/lib/typescript/module/ui/hooks/mutations/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/queries/index.d.ts +0 -13
- package/lib/typescript/module/ui/hooks/queries/index.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/AccountCenterScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/AccountCenterScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/AccountOverviewScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/SessionManagementScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/SessionManagementScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/styles/index.d.ts +0 -4
- package/lib/typescript/module/ui/styles/index.d.ts.map +0 -1
- package/src/ui/components/feedback/index.ts +0 -6
- package/src/ui/components/icon/index.ts +0 -3
- package/src/ui/components/index.ts +0 -15
- package/src/ui/components/modals/index.ts +0 -1
- package/src/ui/components/payment/index.ts +0 -9
- package/src/ui/hooks/index.ts +0 -13
- package/src/ui/hooks/mutations/index.ts +0 -25
- package/src/ui/hooks/queries/index.ts +0 -61
- package/src/ui/screens/AccountCenterScreen.tsx +0 -182
- package/src/ui/screens/AccountOverviewScreen.tsx +0 -696
- package/src/ui/screens/AccountSettingsScreen.tsx +0 -620
- package/src/ui/screens/AccountSwitcherScreen.tsx +0 -1003
- package/src/ui/screens/SessionManagementScreen.tsx +0 -477
- package/src/ui/styles/index.ts +0 -3
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { User, ClientSession } from '@oxyhq/core';
|
|
2
|
+
import { getAccountDisplayName, getAccountFallbackHandle } from '@oxyhq/core';
|
|
3
|
+
|
|
4
|
+
export interface AccountRow {
|
|
5
|
+
sessionId: string;
|
|
6
|
+
isActive: boolean;
|
|
7
|
+
displayName: string;
|
|
8
|
+
secondary: string | null;
|
|
9
|
+
avatarUri?: string;
|
|
10
|
+
user: User | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface BuildAccountRowsInput {
|
|
14
|
+
sessions: ClientSession[] | null | undefined;
|
|
15
|
+
activeSessionId: string | null | undefined;
|
|
16
|
+
user: User | null | undefined;
|
|
17
|
+
locale: string;
|
|
18
|
+
getAvatarUrl: (avatarId: string) => string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Pure builder for `AccountMenu` rows. Extracted so the multi-account display
|
|
23
|
+
* logic can be unit-tested without rendering React Native.
|
|
24
|
+
*
|
|
25
|
+
* Each `sessions[i]` becomes one row. Only the row matching `activeSessionId`
|
|
26
|
+
* carries the loaded `user` payload — the others are placeholders shown by
|
|
27
|
+
* fallback handle. This mirrors how `OxyContext` only hydrates one user at a
|
|
28
|
+
* time.
|
|
29
|
+
*/
|
|
30
|
+
export function buildAccountRows({
|
|
31
|
+
sessions,
|
|
32
|
+
activeSessionId,
|
|
33
|
+
user,
|
|
34
|
+
locale,
|
|
35
|
+
getAvatarUrl,
|
|
36
|
+
}: BuildAccountRowsInput): AccountRow[] {
|
|
37
|
+
return (sessions ?? []).map((session: ClientSession) => {
|
|
38
|
+
const isActive = session.sessionId === activeSessionId;
|
|
39
|
+
const candidate: Partial<User> | null = isActive ? user ?? null : null;
|
|
40
|
+
const displayName = getAccountDisplayName(
|
|
41
|
+
candidate ?? { username: undefined },
|
|
42
|
+
locale,
|
|
43
|
+
);
|
|
44
|
+
const handle = getAccountFallbackHandle(candidate ?? { username: undefined });
|
|
45
|
+
const secondary = (candidate?.email)
|
|
46
|
+
?? (handle && candidate?.username ? `@${handle}` : handle)
|
|
47
|
+
?? null;
|
|
48
|
+
const avatarUri = candidate?.avatar
|
|
49
|
+
? getAvatarUrl(candidate.avatar)
|
|
50
|
+
: undefined;
|
|
51
|
+
return {
|
|
52
|
+
sessionId: session.sessionId,
|
|
53
|
+
isActive,
|
|
54
|
+
displayName,
|
|
55
|
+
secondary,
|
|
56
|
+
avatarUri,
|
|
57
|
+
user: isActive ? user ?? null : null,
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -4,7 +4,7 @@ import { View, Text, Animated, TouchableOpacity, Clipboard, Linking } from 'reac
|
|
|
4
4
|
import { Ionicons } from '@expo/vector-icons';
|
|
5
5
|
import { Button } from '@oxyhq/bloom/button';
|
|
6
6
|
import TextField from '../TextField';
|
|
7
|
-
import
|
|
7
|
+
import FAIRWalletIcon from '../icon/FAIRWalletIcon';
|
|
8
8
|
import { createPaymentStyles } from './paymentStyles';
|
|
9
9
|
import { toast } from '@oxyhq/bloom';
|
|
10
10
|
import type { CardDetails, PaymentColors, PaymentStepAnimations } from './types';
|
|
@@ -4,7 +4,7 @@ import { View, Text, Animated } from 'react-native';
|
|
|
4
4
|
import { Ionicons } from '@expo/vector-icons';
|
|
5
5
|
import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
|
|
6
6
|
import { Button } from '@oxyhq/bloom/button';
|
|
7
|
-
import
|
|
7
|
+
import FAIRWalletIcon from '../icon/FAIRWalletIcon';
|
|
8
8
|
import { createPaymentStyles } from './paymentStyles';
|
|
9
9
|
import type { PaymentMethod, PaymentColors, PaymentStepAnimations } from './types';
|
|
10
10
|
import { useI18n } from '../../hooks/useI18n';
|
|
@@ -25,6 +25,7 @@ import { useAuthOperations } from './hooks/useAuthOperations';
|
|
|
25
25
|
import { useDeviceManagement } from '../hooks/useDeviceManagement';
|
|
26
26
|
import { getStorageKeys, createPlatformStorage, type StorageInterface } from '../utils/storageHelpers';
|
|
27
27
|
import { isInvalidSessionError, isTimeoutOrNetworkError } from '../utils/errorHandlers';
|
|
28
|
+
import { readActiveAuthuser, writeActiveAuthuser } from '../utils/activeAuthuser';
|
|
28
29
|
import type { RouteName } from '../navigation/routes';
|
|
29
30
|
import { showBottomSheet as globalShowBottomSheet } from '../navigation/bottomSheetManager';
|
|
30
31
|
import { useQueryClient } from '@tanstack/react-query';
|
|
@@ -97,6 +98,10 @@ export interface OxyContextState {
|
|
|
97
98
|
|
|
98
99
|
const OxyContext = createContext<OxyContextState | null>(null);
|
|
99
100
|
|
|
101
|
+
// Active-authuser persistence helpers (web localStorage; native no-op) live in
|
|
102
|
+
// `../utils/activeAuthuser` so the session-management and auth-operations hooks
|
|
103
|
+
// can share them without re-importing this 1k-line context file.
|
|
104
|
+
|
|
100
105
|
export interface OxyContextProviderProps {
|
|
101
106
|
children: ReactNode;
|
|
102
107
|
oxyServices?: OxyServices;
|
|
@@ -235,16 +240,58 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
235
240
|
|
|
236
241
|
const storageKeys = useMemo(() => getStorageKeys(storageKeyPrefix), [storageKeyPrefix]);
|
|
237
242
|
|
|
238
|
-
//
|
|
243
|
+
// Storage initialization.
|
|
244
|
+
//
|
|
245
|
+
// `storage` (state) drives render-time gating (`isStorageReady`) and the
|
|
246
|
+
// hooks below. But it is `null` for a brief window after mount while
|
|
247
|
+
// `createPlatformStorage()` resolves (a microtask on web; a dynamic
|
|
248
|
+
// `import()` on native). Any persistence path that fires during that window
|
|
249
|
+
// — e.g. an interactive FedCM sign-in the instant the screen mounts — would
|
|
250
|
+
// read `storage === null` and SILENTLY skip writing the session, leaving the
|
|
251
|
+
// user signed-in in-memory but with nothing to restore on reload.
|
|
252
|
+
//
|
|
253
|
+
// To make persistence robust regardless of timing we ALSO expose the storage
|
|
254
|
+
// as an awaitable promise (`getReadyStorage`). Persistence code awaits the
|
|
255
|
+
// ready instance instead of branching on the possibly-null state, so a write
|
|
256
|
+
// is never silently dropped just because it raced storage init.
|
|
239
257
|
const storageRef = useRef<StorageInterface | null>(null);
|
|
240
258
|
const [storage, setStorage] = useState<StorageInterface | null>(null);
|
|
241
259
|
|
|
260
|
+
// A single, stable deferred that resolves with the initialized storage. Built
|
|
261
|
+
// lazily via a ref initializer so the resolver is captured exactly once and
|
|
262
|
+
// the promise identity is stable across renders.
|
|
263
|
+
const buildStorageDeferred = () => {
|
|
264
|
+
let resolve: (storage: StorageInterface) => void = () => undefined;
|
|
265
|
+
const promise = new Promise<StorageInterface>((res) => {
|
|
266
|
+
resolve = res;
|
|
267
|
+
});
|
|
268
|
+
return { promise, resolve };
|
|
269
|
+
};
|
|
270
|
+
const storageReadyRef = useRef<ReturnType<typeof buildStorageDeferred> | null>(null);
|
|
271
|
+
if (storageReadyRef.current === null) {
|
|
272
|
+
storageReadyRef.current = buildStorageDeferred();
|
|
273
|
+
}
|
|
274
|
+
const storageReady = storageReadyRef.current;
|
|
275
|
+
|
|
276
|
+
// Resolve the storage instance that is guaranteed to be ready. Returns the
|
|
277
|
+
// already-initialized instance synchronously when available, otherwise awaits
|
|
278
|
+
// the init promise. Never resolves to `null`.
|
|
279
|
+
const getReadyStorage = useCallback((): Promise<StorageInterface> => {
|
|
280
|
+
if (storageRef.current) {
|
|
281
|
+
return Promise.resolve(storageRef.current);
|
|
282
|
+
}
|
|
283
|
+
return storageReady.promise;
|
|
284
|
+
}, [storageReady]);
|
|
285
|
+
|
|
242
286
|
useEffect(() => {
|
|
243
287
|
let mounted = true;
|
|
244
288
|
createPlatformStorage()
|
|
245
289
|
.then((storageInstance) => {
|
|
290
|
+
// Resolve the ready-promise even if the component unmounted: in-flight
|
|
291
|
+
// persistence awaiting it must still complete against a real store.
|
|
292
|
+
storageRef.current = storageInstance;
|
|
293
|
+
storageReady.resolve(storageInstance);
|
|
246
294
|
if (mounted) {
|
|
247
|
-
storageRef.current = storageInstance;
|
|
248
295
|
setStorage(storageInstance);
|
|
249
296
|
}
|
|
250
297
|
})
|
|
@@ -262,7 +309,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
262
309
|
return () => {
|
|
263
310
|
mounted = false;
|
|
264
311
|
};
|
|
265
|
-
}, [logger, onError]);
|
|
312
|
+
}, [logger, onError, storageReady]);
|
|
266
313
|
|
|
267
314
|
|
|
268
315
|
// Offline queuing is now handled by TanStack Query mutations
|
|
@@ -375,6 +422,130 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
375
422
|
const clearSessionStateRef = useRef(clearSessionState);
|
|
376
423
|
clearSessionStateRef.current = clearSessionState;
|
|
377
424
|
|
|
425
|
+
// Durable, navigation-safe session persistence.
|
|
426
|
+
//
|
|
427
|
+
// Writes the active-session id and appends the session id to the durable
|
|
428
|
+
// `session_ids` list, awaiting the READY storage instance (never the possibly
|
|
429
|
+
// -null `storage` state) so a write is never dropped because it raced storage
|
|
430
|
+
// init. Callers MUST invoke this BEFORE any work that can trigger a route
|
|
431
|
+
// navigation (`onAuthStateChange`) — navigation can interrupt a still-pending
|
|
432
|
+
// async write, which is exactly what once left `session_ids` empty after a
|
|
433
|
+
// successful sign-in. Shared by the FedCM/popup path and the cold-boot
|
|
434
|
+
// refresh-cookie restore so both land the same durable record.
|
|
435
|
+
const persistSessionDurably = useCallback(async (sessionId: string): Promise<void> => {
|
|
436
|
+
const readyStorage = await getReadyStorage();
|
|
437
|
+
await readyStorage.setItem(storageKeys.activeSessionId, sessionId);
|
|
438
|
+
const existingIds = await readyStorage.getItem(storageKeys.sessionIds);
|
|
439
|
+
let sessionIds: string[] = [];
|
|
440
|
+
try { sessionIds = existingIds ? JSON.parse(existingIds) : []; } catch { /* corrupted storage */ }
|
|
441
|
+
if (!sessionIds.includes(sessionId)) {
|
|
442
|
+
sessionIds.push(sessionId);
|
|
443
|
+
await readyStorage.setItem(storageKeys.sessionIds, JSON.stringify(sessionIds));
|
|
444
|
+
}
|
|
445
|
+
}, [getReadyStorage, storageKeys.activeSessionId, storageKeys.sessionIds]);
|
|
446
|
+
|
|
447
|
+
// Refs so the cold-boot restore can plant session state without widening its
|
|
448
|
+
// dependency array (mirrors the existing ref pattern above).
|
|
449
|
+
const setActiveSessionIdRef = useRef(setActiveSessionId);
|
|
450
|
+
setActiveSessionIdRef.current = setActiveSessionId;
|
|
451
|
+
const loginSuccessRef = useRef(loginSuccess);
|
|
452
|
+
loginSuccessRef.current = loginSuccess;
|
|
453
|
+
const onAuthStateChangeRef = useRef(onAuthStateChange);
|
|
454
|
+
onAuthStateChangeRef.current = onAuthStateChange;
|
|
455
|
+
|
|
456
|
+
// Cold-boot session restore via the secure refresh cookies (web only).
|
|
457
|
+
//
|
|
458
|
+
// Calls `oxyServices.refreshAllSessions()` → `POST /auth/refresh-all` with
|
|
459
|
+
// `credentials: 'include'`. The server rotates every device-local
|
|
460
|
+
// `oxy_rt_${authuser}` cookie in parallel and returns one entry per valid
|
|
461
|
+
// account (Google-style multi-account). On an older server that lacks the
|
|
462
|
+
// multi-account endpoint, the SDK transparently falls back to the legacy
|
|
463
|
+
// `/auth/refresh` single-account path and wraps the result in the same
|
|
464
|
+
// shape, so this caller doesn't branch.
|
|
465
|
+
//
|
|
466
|
+
// Active-account selection: the persisted `oxy_active_authuser` slot index
|
|
467
|
+
// wins when it matches a returned account; otherwise the lowest `authuser`
|
|
468
|
+
// is picked. JS never sees the refresh cookies (httpOnly).
|
|
469
|
+
//
|
|
470
|
+
// Returns `true` when at least one session was restored (caller short-
|
|
471
|
+
// circuits the bearer path); `false` on no signed-in accounts / any failure
|
|
472
|
+
// (caller proceeds unauthenticated through the existing flow — nothing is
|
|
473
|
+
// cleared).
|
|
474
|
+
const restoreViaRefreshCookie = useCallback(async (): Promise<boolean> => {
|
|
475
|
+
if (!isWebBrowser()) {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
let snapshot;
|
|
480
|
+
try {
|
|
481
|
+
snapshot = await oxyServices.refreshAllSessions();
|
|
482
|
+
} catch (fetchError) {
|
|
483
|
+
// Offline / network error — fall through to the cached/stored-session flow.
|
|
484
|
+
if (__DEV__) {
|
|
485
|
+
loggerUtil.debug('Refresh-all cookie restore network error (expected when offline)', { component: 'OxyContext', method: 'restoreViaRefreshCookie' }, fetchError as unknown);
|
|
486
|
+
}
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (snapshot.accounts.length === 0) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Pick the active account: persisted authuser if it still matches a returned
|
|
495
|
+
// account, otherwise the lowest authuser (deterministic). The server has
|
|
496
|
+
// already sorted ascending so [0] is the lowest.
|
|
497
|
+
const persistedAuthuser = readActiveAuthuser();
|
|
498
|
+
const matched = persistedAuthuser !== null
|
|
499
|
+
? snapshot.accounts.find((a) => a.authuser === persistedAuthuser)
|
|
500
|
+
: undefined;
|
|
501
|
+
const activeAccount = matched ?? snapshot.accounts[0];
|
|
502
|
+
|
|
503
|
+
// Plant the active access token. Sibling accounts' access tokens stay in
|
|
504
|
+
// the snapshot (the chooser can drive a per-account refresh via
|
|
505
|
+
// `refreshTokenViaCookie({authuser})` on switch).
|
|
506
|
+
oxyServices.httpService.setTokens(activeAccount.accessToken);
|
|
507
|
+
|
|
508
|
+
// Fetch the full user with the freshly planted token. The refresh-all
|
|
509
|
+
// payload includes a minimal user shape (id, username, name, avatar,
|
|
510
|
+
// email, color) — sufficient for the chooser but the auth store wants the
|
|
511
|
+
// canonical User document for downstream rendering.
|
|
512
|
+
let fullUser: User;
|
|
513
|
+
try {
|
|
514
|
+
fullUser = await oxyServices.getCurrentUser();
|
|
515
|
+
} catch (userError) {
|
|
516
|
+
// Token planted but profile fetch failed (e.g. transient network). Do
|
|
517
|
+
// not claim a restored session; fall through so the stored-session flow
|
|
518
|
+
// can retry. Leave the planted token in place — it is valid and harmless.
|
|
519
|
+
if (__DEV__) {
|
|
520
|
+
loggerUtil.debug('Refresh-all cookie restore: getCurrentUser failed', { component: 'OxyContext', method: 'restoreViaRefreshCookie' }, userError as unknown);
|
|
521
|
+
}
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Build a ClientSession per returned account so the multi-session store
|
|
526
|
+
// reflects every device-local slot, not just the active one. The active
|
|
527
|
+
// account is flagged `isCurrent: true`.
|
|
528
|
+
const now = new Date();
|
|
529
|
+
const clientSessions: ClientSession[] = snapshot.accounts.map((account) => ({
|
|
530
|
+
sessionId: account.sessionId,
|
|
531
|
+
deviceId: '',
|
|
532
|
+
expiresAt: account.expiresAt || new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
533
|
+
lastActive: now.toISOString(),
|
|
534
|
+
userId: account.user?.id,
|
|
535
|
+
isCurrent: account.sessionId === activeAccount.sessionId,
|
|
536
|
+
authuser: account.authuser,
|
|
537
|
+
}));
|
|
538
|
+
|
|
539
|
+
updateSessionsRef.current(clientSessions, { merge: true });
|
|
540
|
+
setActiveSessionIdRef.current(activeAccount.sessionId);
|
|
541
|
+
writeActiveAuthuser(activeAccount.authuser);
|
|
542
|
+
await persistSessionDurably(activeAccount.sessionId);
|
|
543
|
+
|
|
544
|
+
loginSuccessRef.current(fullUser);
|
|
545
|
+
onAuthStateChangeRef.current?.(fullUser);
|
|
546
|
+
return true;
|
|
547
|
+
}, [oxyServices, persistSessionDurably]);
|
|
548
|
+
|
|
378
549
|
const restoreSessionsFromStorage = useCallback(async (): Promise<void> => {
|
|
379
550
|
if (!storage) {
|
|
380
551
|
return;
|
|
@@ -383,6 +554,15 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
383
554
|
setTokenReady(false);
|
|
384
555
|
|
|
385
556
|
try {
|
|
557
|
+
// Web cold-boot fast path: restore the active session from the secure
|
|
558
|
+
// httpOnly refresh cookie before the bearer-protected stored-session
|
|
559
|
+
// validation (which 401s on a hard reload). On success we are signed in
|
|
560
|
+
// from the cookie alone — no FedCM needed. On failure we fall through to
|
|
561
|
+
// the existing stored-session flow below; nothing is cleared.
|
|
562
|
+
if (await restoreViaRefreshCookie()) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
|
|
386
566
|
const storedSessionIdsJson = await storage.getItem(storageKeys.sessionIds);
|
|
387
567
|
const storedSessionIds: string[] = storedSessionIdsJson ? JSON.parse(storedSessionIdsJson) : [];
|
|
388
568
|
const storedActiveSessionId = await storage.getItem(storageKeys.activeSessionId);
|
|
@@ -473,6 +653,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
473
653
|
storage,
|
|
474
654
|
storageKeys.activeSessionId,
|
|
475
655
|
storageKeys.sessionIds,
|
|
656
|
+
restoreViaRefreshCookie,
|
|
476
657
|
]);
|
|
477
658
|
|
|
478
659
|
useEffect(() => {
|
|
@@ -517,8 +698,25 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
517
698
|
updateSessions([clientSession], { merge: true });
|
|
518
699
|
setActiveSessionId(session.sessionId);
|
|
519
700
|
|
|
520
|
-
//
|
|
521
|
-
//
|
|
701
|
+
// Persist to storage BEFORE fetching the profile and BEFORE notifying the
|
|
702
|
+
// auth-state-change callback. The token is planted and the in-memory store
|
|
703
|
+
// is updated above; durably committing the session id here — ahead of
|
|
704
|
+
// `getCurrentUser()` / `loginSuccess` / `onAuthStateChange` — is critical
|
|
705
|
+
// because `onAuthStateChange` triggers a route navigation that can
|
|
706
|
+
// interrupt/supersede a still-pending async write. Persisting first
|
|
707
|
+
// guarantees the durable record lands; that is exactly what was missing
|
|
708
|
+
// when `oxy_session_session_ids` came back empty after a successful FedCM
|
|
709
|
+
// sign-in (the user appeared logged in until reload, then had no session to
|
|
710
|
+
// restore). `persistSessionDurably` awaits the READY storage instance rather
|
|
711
|
+
// than reading the possibly-null `storage` state, so a sign-in fired the
|
|
712
|
+
// instant the screen mounts (before storage-init populates state) is not
|
|
713
|
+
// silently dropped.
|
|
714
|
+
await persistSessionDurably(session.sessionId);
|
|
715
|
+
|
|
716
|
+
// Fetch the full user profile now that we have a valid access token and the
|
|
717
|
+
// session is durably persisted. The session only carries MinimalUserData;
|
|
718
|
+
// the store and callbacks expect a full User. The navigation kicked off by
|
|
719
|
+
// `onAuthStateChange` now happens only after the durable write is committed.
|
|
522
720
|
let fullUser: User;
|
|
523
721
|
try {
|
|
524
722
|
fullUser = await oxyServices.getCurrentUser();
|
|
@@ -529,19 +727,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
529
727
|
}
|
|
530
728
|
loginSuccess(fullUser);
|
|
531
729
|
onAuthStateChange?.(fullUser);
|
|
532
|
-
|
|
533
|
-
// Persist to storage
|
|
534
|
-
if (storage) {
|
|
535
|
-
await storage.setItem(storageKeys.activeSessionId, session.sessionId);
|
|
536
|
-
const existingIds = await storage.getItem(storageKeys.sessionIds);
|
|
537
|
-
let sessionIds: string[] = [];
|
|
538
|
-
try { sessionIds = existingIds ? JSON.parse(existingIds) : []; } catch { /* corrupted storage */ }
|
|
539
|
-
if (!sessionIds.includes(session.sessionId)) {
|
|
540
|
-
sessionIds.push(session.sessionId);
|
|
541
|
-
await storage.setItem(storageKeys.sessionIds, JSON.stringify(sessionIds));
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
}, [oxyServices, updateSessions, setActiveSessionId, loginSuccess, onAuthStateChange, storage, storageKeys]);
|
|
730
|
+
}, [oxyServices, updateSessions, setActiveSessionId, loginSuccess, onAuthStateChange, persistSessionDurably]);
|
|
545
731
|
|
|
546
732
|
// Enable web SSO only after local storage check completes and no user found
|
|
547
733
|
const shouldTryWebSSO = isWebBrowser() && tokenReady && !user && initialized;
|
|
@@ -8,6 +8,8 @@ import { handleAuthError, isInvalidSessionError } from '../../utils/errorHandler
|
|
|
8
8
|
import type { StorageInterface } from '../../utils/storageHelpers';
|
|
9
9
|
import type { OxyServices } from '@oxyhq/core';
|
|
10
10
|
import { SignatureService } from '@oxyhq/core';
|
|
11
|
+
import { isWebBrowser } from '../../hooks/useWebSSO';
|
|
12
|
+
import { clearActiveAuthuser } from '../../utils/activeAuthuser';
|
|
11
13
|
|
|
12
14
|
/** Type guard for error objects with optional code and status properties */
|
|
13
15
|
function isErrorWithCodeOrStatus(error: unknown): error is { code?: string; status?: number; message?: string } {
|
|
@@ -300,7 +302,19 @@ export const useAuthOperations = ({
|
|
|
300
302
|
|
|
301
303
|
try {
|
|
302
304
|
const sessionToLogout = targetSessionId || activeSessionId;
|
|
303
|
-
|
|
305
|
+
// Web multi-account: when the target session carries an `authuser`
|
|
306
|
+
// slot index it is backed by an httpOnly `oxy_rt_${n}` cookie. Use
|
|
307
|
+
// the cookie-cleared logout endpoint so the server can `Set-Cookie`
|
|
308
|
+
// an immediate expiry alongside revoking the family. Native and
|
|
309
|
+
// legacy sessions (no `authuser` plumbed yet) fall through to the
|
|
310
|
+
// bearer-protected endpoint.
|
|
311
|
+
const targetSession = sessionsRef.current.find((s) => s.sessionId === sessionToLogout);
|
|
312
|
+
const targetAuthuser = targetSession?.authuser;
|
|
313
|
+
if (isWebBrowser() && typeof targetAuthuser === 'number') {
|
|
314
|
+
await oxyServices.logoutSessionByAuthuser(targetAuthuser);
|
|
315
|
+
} else {
|
|
316
|
+
await oxyServices.logoutSession(activeSessionId, sessionToLogout);
|
|
317
|
+
}
|
|
304
318
|
|
|
305
319
|
const filteredSessions = sessionsRef.current.filter((session) => session.sessionId !== sessionToLogout);
|
|
306
320
|
updateSessions(filteredSessions, { merge: false });
|
|
@@ -355,7 +369,27 @@ export const useAuthOperations = ({
|
|
|
355
369
|
}
|
|
356
370
|
|
|
357
371
|
try {
|
|
358
|
-
|
|
372
|
+
// Semantics intentionally diverge by platform to match user expectation:
|
|
373
|
+
// - Web: "Sign out of all accounts" = sign out every device-local
|
|
374
|
+
// account on THIS device. The cookie endpoint is the only path
|
|
375
|
+
// that can `Set-Cookie` an immediate expiry on every
|
|
376
|
+
// `oxy_rt_${n}` slot (plus legacy `oxy_rt`) AND revoke every
|
|
377
|
+
// presented family server-side. The bearer-protected
|
|
378
|
+
// `logoutAllSessions(activeSessionId)` would only revoke the
|
|
379
|
+
// active user's sessions across devices and leave sibling
|
|
380
|
+
// accounts' cookies sitting on this device — wrong UX for the
|
|
381
|
+
// chooser's "Sign out of all accounts".
|
|
382
|
+
// - Native: there are no per-account cookies; "Sign out of all"
|
|
383
|
+
// keeps its long-standing "revoke every session of THIS user"
|
|
384
|
+
// meaning via the bearer endpoint.
|
|
385
|
+
// After clearing on web, also drop the persisted active-authuser so
|
|
386
|
+
// the next cold boot starts from a clean slate.
|
|
387
|
+
if (isWebBrowser()) {
|
|
388
|
+
await oxyServices.logoutAllSessionsViaCookie();
|
|
389
|
+
clearActiveAuthuser();
|
|
390
|
+
} else {
|
|
391
|
+
await oxyServices.logoutAllSessions(activeSessionId);
|
|
392
|
+
}
|
|
359
393
|
await clearSessionState();
|
|
360
394
|
} catch (error) {
|
|
361
395
|
handleAuthError(error, {
|
|
@@ -14,6 +14,12 @@ export const mutationKeys = {
|
|
|
14
14
|
uploadAvatar: ['mutation', 'account', 'uploadAvatar'] as const,
|
|
15
15
|
updateSettings: ['mutation', 'account', 'updateSettings'] as const,
|
|
16
16
|
updatePrivacySettings: ['mutation', 'account', 'updatePrivacySettings'] as const,
|
|
17
|
+
updateNotificationPreferences: [
|
|
18
|
+
'mutation',
|
|
19
|
+
'account',
|
|
20
|
+
'updateNotificationPreferences',
|
|
21
|
+
] as const,
|
|
22
|
+
updateUserPreferences: ['mutation', 'account', 'updateUserPreferences'] as const,
|
|
17
23
|
uploadFile: ['mutation', 'account', 'uploadFile'] as const,
|
|
18
24
|
},
|
|
19
25
|
|
|
@@ -25,4 +31,9 @@ export const mutationKeys = {
|
|
|
25
31
|
updateDeviceName: ['mutation', 'session', 'updateDeviceName'] as const,
|
|
26
32
|
removeDevice: ['mutation', 'session', 'removeDevice'] as const,
|
|
27
33
|
},
|
|
34
|
+
|
|
35
|
+
// Connected apps (FedCM grants)
|
|
36
|
+
connectedApps: {
|
|
37
|
+
revoke: ['mutation', 'connectedApps', 'revoke'] as const,
|
|
38
|
+
},
|
|
28
39
|
} as const;
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
2
2
|
import { authenticatedApiCall } from '@oxyhq/core';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
3
|
+
import type {
|
|
4
|
+
AssetUploadInput,
|
|
5
|
+
NotificationPreferences,
|
|
6
|
+
PrivacySettings,
|
|
7
|
+
User,
|
|
8
|
+
UserPreferences,
|
|
9
|
+
} from '@oxyhq/core';
|
|
10
|
+
import {
|
|
11
|
+
queryKeys,
|
|
12
|
+
invalidateAccountQueries,
|
|
13
|
+
invalidateConnectedAppsQueries,
|
|
14
|
+
invalidateUserQueries,
|
|
15
|
+
invalidateSessionQueries,
|
|
16
|
+
} from '../queries/queryKeys';
|
|
5
17
|
import { mutationKeys } from './mutationKeys';
|
|
6
18
|
import { useOxy } from '../../context/OxyContext';
|
|
7
19
|
import { toast } from '@oxyhq/bloom';
|
|
@@ -505,6 +517,146 @@ interface UploadResult {
|
|
|
505
517
|
id?: string;
|
|
506
518
|
}
|
|
507
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Update the authenticated user's notification preferences with optimistic
|
|
522
|
+
* updates. Persisted on the User document via `PUT /users/me` — same cache-
|
|
523
|
+
* invalidation behaviour as `useUpdateProfile`.
|
|
524
|
+
*/
|
|
525
|
+
export const useUpdateNotificationPreferences = () => {
|
|
526
|
+
const { oxyServices, activeSessionId } = useOxy();
|
|
527
|
+
const queryClient = useQueryClient();
|
|
528
|
+
|
|
529
|
+
return useMutation({
|
|
530
|
+
mutationKey: [...mutationKeys.account.updateNotificationPreferences],
|
|
531
|
+
mutationFn: async (preferences: Partial<NotificationPreferences>) => {
|
|
532
|
+
return authenticatedApiCall<User>(
|
|
533
|
+
oxyServices,
|
|
534
|
+
activeSessionId,
|
|
535
|
+
() => oxyServices.updateNotificationPreferences(preferences)
|
|
536
|
+
);
|
|
537
|
+
},
|
|
538
|
+
onMutate: async (preferences) => {
|
|
539
|
+
await queryClient.cancelQueries({ queryKey: queryKeys.accounts.current() });
|
|
540
|
+
const previousUser = queryClient.getQueryData<User>(queryKeys.accounts.current());
|
|
541
|
+
|
|
542
|
+
if (previousUser) {
|
|
543
|
+
queryClient.setQueryData<User>(queryKeys.accounts.current(), {
|
|
544
|
+
...previousUser,
|
|
545
|
+
notificationPreferences: {
|
|
546
|
+
...previousUser.notificationPreferences,
|
|
547
|
+
...preferences,
|
|
548
|
+
},
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return { previousUser };
|
|
553
|
+
},
|
|
554
|
+
onError: (error, _preferences, context) => {
|
|
555
|
+
if (context?.previousUser) {
|
|
556
|
+
const current = queryClient.getQueryData<User>(queryKeys.accounts.current());
|
|
557
|
+
if (current) {
|
|
558
|
+
queryClient.setQueryData<User>(queryKeys.accounts.current(), {
|
|
559
|
+
...current,
|
|
560
|
+
notificationPreferences: context.previousUser.notificationPreferences,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
toast.error(
|
|
565
|
+
error instanceof Error
|
|
566
|
+
? error.message
|
|
567
|
+
: 'Failed to update notification preferences'
|
|
568
|
+
);
|
|
569
|
+
},
|
|
570
|
+
onSuccess: (data) => {
|
|
571
|
+
queryClient.setQueryData(queryKeys.accounts.current(), data);
|
|
572
|
+
useAuthStore.getState().setUser(data);
|
|
573
|
+
invalidateAccountQueries(queryClient);
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Update the authenticated user's general preferences (language, theme,
|
|
580
|
+
* reduce-motion, timezone). Persisted on the User document via
|
|
581
|
+
* `PUT /users/me`.
|
|
582
|
+
*/
|
|
583
|
+
export const useUpdateUserPreferences = () => {
|
|
584
|
+
const { oxyServices, activeSessionId } = useOxy();
|
|
585
|
+
const queryClient = useQueryClient();
|
|
586
|
+
|
|
587
|
+
return useMutation({
|
|
588
|
+
mutationKey: [...mutationKeys.account.updateUserPreferences],
|
|
589
|
+
mutationFn: async (preferences: Partial<UserPreferences>) => {
|
|
590
|
+
return authenticatedApiCall<User>(
|
|
591
|
+
oxyServices,
|
|
592
|
+
activeSessionId,
|
|
593
|
+
() => oxyServices.updateUserPreferences(preferences)
|
|
594
|
+
);
|
|
595
|
+
},
|
|
596
|
+
onMutate: async (preferences) => {
|
|
597
|
+
await queryClient.cancelQueries({ queryKey: queryKeys.accounts.current() });
|
|
598
|
+
const previousUser = queryClient.getQueryData<User>(queryKeys.accounts.current());
|
|
599
|
+
|
|
600
|
+
if (previousUser) {
|
|
601
|
+
queryClient.setQueryData<User>(queryKeys.accounts.current(), {
|
|
602
|
+
...previousUser,
|
|
603
|
+
userPreferences: {
|
|
604
|
+
...previousUser.userPreferences,
|
|
605
|
+
...preferences,
|
|
606
|
+
},
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
return { previousUser };
|
|
611
|
+
},
|
|
612
|
+
onError: (error, _preferences, context) => {
|
|
613
|
+
if (context?.previousUser) {
|
|
614
|
+
const current = queryClient.getQueryData<User>(queryKeys.accounts.current());
|
|
615
|
+
if (current) {
|
|
616
|
+
queryClient.setQueryData<User>(queryKeys.accounts.current(), {
|
|
617
|
+
...current,
|
|
618
|
+
userPreferences: context.previousUser.userPreferences,
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
toast.error(error instanceof Error ? error.message : 'Failed to update preferences');
|
|
623
|
+
},
|
|
624
|
+
onSuccess: (data) => {
|
|
625
|
+
queryClient.setQueryData(queryKeys.accounts.current(), data);
|
|
626
|
+
useAuthStore.getState().setUser(data);
|
|
627
|
+
invalidateAccountQueries(queryClient);
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Revoke the authenticated user's authorization for a specific RP origin.
|
|
634
|
+
* Removes the FedCM grant so the origin no longer appears in the user's
|
|
635
|
+
* "Connected apps" list — next sign-in from that origin will require explicit
|
|
636
|
+
* re-consent.
|
|
637
|
+
*/
|
|
638
|
+
export const useRevokeAuthorizedApp = () => {
|
|
639
|
+
const { oxyServices, activeSessionId } = useOxy();
|
|
640
|
+
const queryClient = useQueryClient();
|
|
641
|
+
|
|
642
|
+
return useMutation({
|
|
643
|
+
mutationKey: [...mutationKeys.connectedApps.revoke],
|
|
644
|
+
mutationFn: async (origin: string) => {
|
|
645
|
+
return authenticatedApiCall<void>(oxyServices, activeSessionId, () =>
|
|
646
|
+
oxyServices.revokeAuthorizedApp(origin)
|
|
647
|
+
);
|
|
648
|
+
},
|
|
649
|
+
onSuccess: () => {
|
|
650
|
+
invalidateConnectedAppsQueries(queryClient);
|
|
651
|
+
},
|
|
652
|
+
onError: (error) => {
|
|
653
|
+
toast.error(
|
|
654
|
+
error instanceof Error ? error.message : 'Failed to revoke authorized app'
|
|
655
|
+
);
|
|
656
|
+
},
|
|
657
|
+
});
|
|
658
|
+
};
|
|
659
|
+
|
|
508
660
|
/**
|
|
509
661
|
* Upload file with authentication handling and progress tracking
|
|
510
662
|
*/
|