@oxyhq/services 16.0.0 → 17.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 +21 -51
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/client.js +0 -14
- package/lib/commonjs/ui/client.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAccountDialog.js +764 -0
- package/lib/commonjs/ui/components/OxyAccountDialog.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +11 -6
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +10 -21
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +25 -112
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/RequireOxyAuth.js +299 -0
- package/lib/commonjs/ui/components/RequireOxyAuth.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +106 -2
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +19 -30
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +37 -267
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -1
- package/lib/commonjs/ui/index.js +5 -40
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/navigation/accountDialogManager.js +91 -0
- package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -0
- package/lib/commonjs/ui/navigation/routes.js +0 -2
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +4 -3
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/session/createSessionClient.js +10 -2
- package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
- package/lib/module/index.js +18 -15
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/client.js +1 -2
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/OxyAccountDialog.js +761 -0
- package/lib/module/ui/components/OxyAccountDialog.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +11 -6
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +10 -21
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js +26 -112
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/RequireOxyAuth.js +294 -0
- package/lib/module/ui/components/RequireOxyAuth.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +107 -3
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +1 -1
- package/lib/module/ui/hooks/useAuth.js +19 -30
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/hooks/useSwitchableAccounts.js +38 -267
- package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -1
- package/lib/module/ui/index.js +1 -5
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/navigation/accountDialogManager.js +81 -0
- package/lib/module/ui/navigation/accountDialogManager.js.map +1 -0
- package/lib/module/ui/navigation/routes.js +0 -2
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +4 -3
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/session/createSessionClient.js +10 -2
- package/lib/module/ui/session/createSessionClient.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -11
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/client.d.ts +0 -4
- package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts +35 -0
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +11 -23
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +55 -0
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +13 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +13 -152
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +2 -5
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +49 -0
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -0
- 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/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +9 -2
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +9 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -11
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +0 -4
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts +35 -0
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +11 -23
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +55 -0
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts +13 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +13 -152
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +2 -5
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +49 -0
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -0
- 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/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/createSessionClient.d.ts +9 -2
- package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +9 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +21 -26
- package/src/ui/client.ts +0 -4
- package/src/ui/components/OxyAccountDialog.tsx +760 -0
- package/src/ui/components/OxyProvider.tsx +12 -6
- package/src/ui/components/OxySignInButton.tsx +10 -21
- package/src/ui/components/ProfileButton.tsx +23 -126
- package/src/ui/components/RequireOxyAuth.tsx +266 -0
- package/src/ui/context/OxyContext.tsx +146 -7
- package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
- package/src/ui/hooks/useAuth.ts +19 -31
- package/src/ui/hooks/useSwitchableAccounts.ts +42 -376
- package/src/ui/index.ts +2 -5
- package/src/ui/navigation/accountDialogManager.ts +84 -0
- package/src/ui/navigation/routes.ts +0 -4
- package/src/ui/screens/ManageAccountScreen.tsx +3 -2
- package/src/ui/session/createSessionClient.ts +9 -1
- package/src/ui/types/navigation.ts +9 -0
- package/lib/commonjs/ui/components/AccountMenu.js +0 -598
- package/lib/commonjs/ui/components/AccountMenu.js.map +0 -1
- package/lib/commonjs/ui/components/AccountMenuButton.js +0 -135
- package/lib/commonjs/ui/components/AccountMenuButton.js.map +0 -1
- package/lib/commonjs/ui/components/AccountSwitcher.js +0 -780
- package/lib/commonjs/ui/components/AccountSwitcher.js.map +0 -1
- package/lib/commonjs/ui/components/AnotherDeviceQR.js +0 -116
- package/lib/commonjs/ui/components/AnotherDeviceQR.js.map +0 -1
- package/lib/commonjs/ui/components/ProfileMenu.js +0 -518
- package/lib/commonjs/ui/components/ProfileMenu.js.map +0 -1
- package/lib/commonjs/ui/components/SignInAccountChooser.js +0 -189
- package/lib/commonjs/ui/components/SignInAccountChooser.js.map +0 -1
- package/lib/commonjs/ui/components/SignInModal.js +0 -600
- package/lib/commonjs/ui/components/SignInModal.js.map +0 -1
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js +0 -501
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js.map +0 -1
- package/lib/commonjs/ui/hooks/usePasswordSignIn.js +0 -170
- package/lib/commonjs/ui/hooks/usePasswordSignIn.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +0 -51
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +0 -312
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +0 -1
- package/lib/commonjs/utils/deviceFlowSignIn.js +0 -109
- package/lib/commonjs/utils/deviceFlowSignIn.js.map +0 -1
- package/lib/module/ui/components/AccountMenu.js +0 -593
- package/lib/module/ui/components/AccountMenu.js.map +0 -1
- package/lib/module/ui/components/AccountMenuButton.js +0 -130
- package/lib/module/ui/components/AccountMenuButton.js.map +0 -1
- package/lib/module/ui/components/AccountSwitcher.js +0 -774
- package/lib/module/ui/components/AccountSwitcher.js.map +0 -1
- package/lib/module/ui/components/AnotherDeviceQR.js +0 -110
- package/lib/module/ui/components/AnotherDeviceQR.js.map +0 -1
- package/lib/module/ui/components/ProfileMenu.js +0 -514
- package/lib/module/ui/components/ProfileMenu.js.map +0 -1
- package/lib/module/ui/components/SignInAccountChooser.js +0 -183
- package/lib/module/ui/components/SignInAccountChooser.js.map +0 -1
- package/lib/module/ui/components/SignInModal.js +0 -591
- package/lib/module/ui/components/SignInModal.js.map +0 -1
- package/lib/module/ui/hooks/useOxyAuthSession.js +0 -495
- package/lib/module/ui/hooks/useOxyAuthSession.js.map +0 -1
- package/lib/module/ui/hooks/usePasswordSignIn.js +0 -165
- package/lib/module/ui/hooks/usePasswordSignIn.js.map +0 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +0 -48
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +0 -306
- package/lib/module/ui/screens/OxyAuthScreen.js.map +0 -1
- package/lib/module/utils/deviceFlowSignIn.js +0 -106
- package/lib/module/utils/deviceFlowSignIn.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +0 -47
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts +0 -26
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts +0 -46
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts +0 -34
- package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +0 -49
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts +0 -29
- package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts +0 -28
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts +0 -105
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts +0 -31
- package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts +0 -11
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts +0 -22
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +0 -97
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountMenu.d.ts +0 -47
- package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts +0 -26
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +0 -46
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts +0 -34
- package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts +0 -49
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts +0 -29
- package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/SignInModal.d.ts +0 -28
- package/lib/typescript/module/ui/components/SignInModal.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts +0 -105
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts +0 -31
- package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts +0 -11
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts +0 -22
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +0 -1
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +0 -97
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +0 -1
- package/src/ui/components/AccountMenu.tsx +0 -645
- package/src/ui/components/AccountMenuButton.tsx +0 -126
- package/src/ui/components/AccountSwitcher.tsx +0 -751
- package/src/ui/components/AnotherDeviceQR.tsx +0 -119
- package/src/ui/components/ProfileMenu.tsx +0 -564
- package/src/ui/components/SignInAccountChooser.tsx +0 -162
- package/src/ui/components/SignInModal.tsx +0 -530
- package/src/ui/hooks/useOxyAuthSession.ts +0 -635
- package/src/ui/hooks/usePasswordSignIn.ts +0 -207
- package/src/ui/screens/AccountSwitcherScreen.tsx +0 -43
- package/src/ui/screens/OxyAuthScreen.tsx +0 -324
- package/src/utils/__tests__/deviceFlowSignIn.test.ts +0 -231
- package/src/utils/deviceFlowSignIn.ts +0 -152
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
useState,
|
|
10
10
|
type ReactNode,
|
|
11
11
|
} from 'react';
|
|
12
|
+
import { Linking } from 'react-native';
|
|
12
13
|
import { OxyServices, oxyClient } from '@oxyhq/core';
|
|
13
14
|
import type {
|
|
14
15
|
User,
|
|
@@ -19,14 +20,21 @@ import type {
|
|
|
19
20
|
ClientSession,
|
|
20
21
|
AuthStateStore,
|
|
21
22
|
PersistedAuthState,
|
|
23
|
+
AccountDialogController,
|
|
24
|
+
AccountDialogView,
|
|
22
25
|
} from '@oxyhq/core';
|
|
23
26
|
import {
|
|
24
27
|
KeyManager,
|
|
25
28
|
runSessionColdBoot,
|
|
26
29
|
installAuthRefreshHandler,
|
|
27
30
|
startTokenRefreshScheduler,
|
|
31
|
+
createAccountDialogController,
|
|
28
32
|
logger as loggerUtil,
|
|
29
33
|
} from '@oxyhq/core';
|
|
34
|
+
import {
|
|
35
|
+
registerAccountDialogControls,
|
|
36
|
+
notifyAccountDialogVisibility,
|
|
37
|
+
} from '../navigation/accountDialogManager';
|
|
30
38
|
import { useAuthStore, type AuthState } from '../stores/authStore';
|
|
31
39
|
import { useShallow } from 'zustand/react/shallow';
|
|
32
40
|
import type { UseFollowHook } from '../hooks/useFollow.types';
|
|
@@ -157,6 +165,22 @@ export interface OxyContextState {
|
|
|
157
165
|
showBottomSheet?: (screenOrConfig: RouteName | { screen: RouteName; props?: Record<string, unknown> }) => void;
|
|
158
166
|
openAvatarPicker: () => void;
|
|
159
167
|
|
|
168
|
+
// Unified account dialog (the single switcher + sign-in surface). The headless
|
|
169
|
+
// state machine lives in `@oxyhq/core`; `OxyAccountDialog` (mounted by
|
|
170
|
+
// `OxyProvider`) binds to it. `null` in the no-provider loading state.
|
|
171
|
+
/** The headless controller driving {@link openAccountDialog}. `null` before mount. */
|
|
172
|
+
accountDialogController: AccountDialogController | null;
|
|
173
|
+
/** Whether the unified account dialog is currently presented. */
|
|
174
|
+
isAccountDialogOpen: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Open the unified account dialog. `accounts` (default) shows the switcher;
|
|
177
|
+
* `signin` / `add` open the sign-in entry. Replaces every prior device/account
|
|
178
|
+
* surface and the standalone sign-in modal.
|
|
179
|
+
*/
|
|
180
|
+
openAccountDialog: (view?: AccountDialogView) => void;
|
|
181
|
+
/** Dismiss the unified account dialog and cancel any in-flight sign-in flow. */
|
|
182
|
+
closeAccountDialog: () => void;
|
|
183
|
+
|
|
160
184
|
// Unified account graph (self, owned orgs/projects/bots, accounts shared with
|
|
161
185
|
// the caller). The cryptographic Commons/DID "identity" is a SEPARATE concept.
|
|
162
186
|
//
|
|
@@ -367,6 +391,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
367
391
|
userRef.current = user;
|
|
368
392
|
isAuthenticatedRef.current = isAuthenticated;
|
|
369
393
|
const [initialized, setInitialized] = useState(false);
|
|
394
|
+
const [accountDialogOpen, setAccountDialogOpen] = useState(false);
|
|
370
395
|
const setAuthState = useAuthStore.setState;
|
|
371
396
|
|
|
372
397
|
// Keep the shared `oxyClient` singleton's token store in lockstep with the
|
|
@@ -505,18 +530,47 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
505
530
|
const markAuthResolvedRef = useRef(markAuthResolved);
|
|
506
531
|
markAuthResolvedRef.current = markAuthResolved;
|
|
507
532
|
|
|
533
|
+
// Re-boot indirection: the SessionClient is built in the ref initializer below
|
|
534
|
+
// (before `runColdBoot` is defined), but its `onSessionAppeared` must re-run the
|
|
535
|
+
// cold boot to self-acquire when a sibling signs in on this device. A ref bridges
|
|
536
|
+
// the ordering; it is assigned right after `runColdBoot` is declared.
|
|
537
|
+
const runColdBootRef = useRef<(() => Promise<void>) | null>(null);
|
|
538
|
+
|
|
508
539
|
// Server-authoritative device session client. Built ONCE per `oxyServices`
|
|
509
540
|
// instance. `onUnauthenticated` (a device signout-all pushed over the socket,
|
|
510
541
|
// or bootstrapped as zero-account) clears the persisted store + local state so
|
|
511
542
|
// a reload does not try to restore a session the device no longer has.
|
|
543
|
+
// `signedOutSocketAuth` + `onSessionAppeared` power the signed-out sync channel:
|
|
544
|
+
// an idle tab joins its `device:<id>` room (web via the `oxy_device` cookie,
|
|
545
|
+
// native via the shared device token) and self-acquires on a sibling sign-in.
|
|
512
546
|
const sessionClientPairRef = useRef<ReturnType<typeof createSessionClient> | null>(null);
|
|
513
547
|
if (!sessionClientPairRef.current) {
|
|
514
|
-
sessionClientPairRef.current = createSessionClient(
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
548
|
+
sessionClientPairRef.current = createSessionClient(
|
|
549
|
+
oxyServices,
|
|
550
|
+
authStore,
|
|
551
|
+
() => {
|
|
552
|
+
clearPersistedAuthSafe(authStore, logger);
|
|
553
|
+
void clearSessionStateRef.current().catch((clearError) => {
|
|
554
|
+
logger('Failed to clear local state on remote sign-out', clearError);
|
|
555
|
+
});
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
signedOutSocketAuth: async () => {
|
|
559
|
+
// Web (`*.oxy.so`): the first-party `oxy_device` cookie rides the
|
|
560
|
+
// same-site handshake automatically — just connect.
|
|
561
|
+
if (isWebBrowser()) return true;
|
|
562
|
+
// Native (no cookie jar): present the shared device token if we have one.
|
|
563
|
+
try {
|
|
564
|
+
return (await authStore.loadDeviceToken()) ?? false;
|
|
565
|
+
} catch {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
},
|
|
569
|
+
onSessionAppeared: () => {
|
|
570
|
+
void runColdBootRef.current?.();
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
);
|
|
520
574
|
}
|
|
521
575
|
const { client: sessionClient, host: sessionClientHost } = sessionClientPairRef.current;
|
|
522
576
|
|
|
@@ -804,6 +858,61 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
804
858
|
[commitSession],
|
|
805
859
|
);
|
|
806
860
|
|
|
861
|
+
// ── Unified account dialog ─────────────────────────────────────────────────
|
|
862
|
+
// The single account-chooser + sign-in surface. Built ONCE per provider mount
|
|
863
|
+
// and bound to the live `oxyServices` + `sessionClient` + this provider's
|
|
864
|
+
// `handleWebSession` commit funnel. `handleWebSession` is threaded through a ref
|
|
865
|
+
// so the controller keeps a STABLE `commitSession` (rebuilding the controller
|
|
866
|
+
// on every commit-identity change would drop its subscription + state).
|
|
867
|
+
const handleWebSessionRef = useRef(handleWebSession);
|
|
868
|
+
handleWebSessionRef.current = handleWebSession;
|
|
869
|
+
|
|
870
|
+
const accountDialogControllerRef = useRef<AccountDialogController | null>(null);
|
|
871
|
+
if (!accountDialogControllerRef.current) {
|
|
872
|
+
accountDialogControllerRef.current = createAccountDialogController({
|
|
873
|
+
oxyServices,
|
|
874
|
+
sessionClient,
|
|
875
|
+
clientId,
|
|
876
|
+
locale: currentLanguage,
|
|
877
|
+
commitSession: (session) => handleWebSessionRef.current(session),
|
|
878
|
+
onSignedIn: () => setAccountDialogOpen(false),
|
|
879
|
+
openUrl: (url) => {
|
|
880
|
+
void Linking.openURL(url);
|
|
881
|
+
},
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
const accountDialogController = accountDialogControllerRef.current;
|
|
885
|
+
|
|
886
|
+
const openAccountDialog = useCallback((view?: AccountDialogView): void => {
|
|
887
|
+
accountDialogControllerRef.current?.setView(view ?? 'accounts');
|
|
888
|
+
setAccountDialogOpen(true);
|
|
889
|
+
}, []);
|
|
890
|
+
|
|
891
|
+
const closeAccountDialog = useCallback((): void => {
|
|
892
|
+
accountDialogControllerRef.current?.cancelSignIn();
|
|
893
|
+
setAccountDialogOpen(false);
|
|
894
|
+
}, []);
|
|
895
|
+
|
|
896
|
+
// Start driving the dialog on mount; tear it down on unmount.
|
|
897
|
+
useEffect(() => {
|
|
898
|
+
const controller = accountDialogControllerRef.current;
|
|
899
|
+
controller?.start();
|
|
900
|
+
return () => controller?.destroy();
|
|
901
|
+
}, []);
|
|
902
|
+
|
|
903
|
+
// Expose the live open/close controls to the imperative manager so
|
|
904
|
+
// `showSignInModal()` (and any app-level imperative "sign in" handler) works.
|
|
905
|
+
useEffect(
|
|
906
|
+
() => registerAccountDialogControls({ open: openAccountDialog, close: closeAccountDialog }),
|
|
907
|
+
[openAccountDialog, closeAccountDialog],
|
|
908
|
+
);
|
|
909
|
+
|
|
910
|
+
// Broadcast visibility so `OxySignInButton`'s "Signing in…" affordance stays
|
|
911
|
+
// accurate regardless of what opened or dismissed the dialog.
|
|
912
|
+
useEffect(() => {
|
|
913
|
+
notifyAccountDialogVisibility(accountDialogOpen);
|
|
914
|
+
}, [accountDialogOpen]);
|
|
915
|
+
|
|
807
916
|
// Keyless password sign-in: username/email + password.
|
|
808
917
|
const signInWithPassword = useCallback(
|
|
809
918
|
async (
|
|
@@ -908,6 +1017,18 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
908
1017
|
},
|
|
909
1018
|
onSignedOut: () => {
|
|
910
1019
|
markAuthResolvedRef.current();
|
|
1020
|
+
// Open the signed-out realtime channel so this idle tab joins its
|
|
1021
|
+
// `device:<id>` room (web `oxy_device` cookie / native device token)
|
|
1022
|
+
// and self-acquires when a sibling signs in. Idempotent, best-effort.
|
|
1023
|
+
void sessionClient.start().catch((startError) => {
|
|
1024
|
+
if (__DEV__) {
|
|
1025
|
+
loggerUtil.debug(
|
|
1026
|
+
'signed-out socket start failed (non-fatal)',
|
|
1027
|
+
{ component: 'OxyContext', method: 'runColdBoot' },
|
|
1028
|
+
startError as unknown,
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
911
1032
|
},
|
|
912
1033
|
onStepError: (id, error) => {
|
|
913
1034
|
if (__DEV__) {
|
|
@@ -931,7 +1052,10 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
931
1052
|
// Backstop: resolve on every exit path so the gate can never hang.
|
|
932
1053
|
markAuthResolvedRef.current();
|
|
933
1054
|
}
|
|
934
|
-
}, [oxyServices, authStore]);
|
|
1055
|
+
}, [oxyServices, authStore, sessionClient]);
|
|
1056
|
+
// Bridge for `onSessionAppeared` (SessionClient) → re-run the cold boot to
|
|
1057
|
+
// self-acquire when a sibling signs in on this device while this tab is idle.
|
|
1058
|
+
runColdBootRef.current = runColdBoot;
|
|
935
1059
|
|
|
936
1060
|
useEffect(() => {
|
|
937
1061
|
if (!storage || initialized) {
|
|
@@ -1018,6 +1142,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1018
1142
|
useEffect(() => {
|
|
1019
1143
|
if (isAuthenticated && initialized && tokenReady) {
|
|
1020
1144
|
refreshAccounts();
|
|
1145
|
+
// Reload the dialog's own account graph too, so a session restored OUTSIDE
|
|
1146
|
+
// the dialog (cold boot / password sign-in) surfaces its graph accounts.
|
|
1147
|
+
void accountDialogControllerRef.current?.refresh();
|
|
1021
1148
|
}
|
|
1022
1149
|
}, [isAuthenticated, initialized, tokenReady, refreshAccounts]);
|
|
1023
1150
|
|
|
@@ -1115,6 +1242,10 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1115
1242
|
useFollow: useFollowHook,
|
|
1116
1243
|
showBottomSheet: showBottomSheetForContext,
|
|
1117
1244
|
openAvatarPicker,
|
|
1245
|
+
accountDialogController,
|
|
1246
|
+
isAccountDialogOpen: accountDialogOpen,
|
|
1247
|
+
openAccountDialog,
|
|
1248
|
+
closeAccountDialog,
|
|
1118
1249
|
accounts,
|
|
1119
1250
|
switchToAccount,
|
|
1120
1251
|
refreshAccounts,
|
|
@@ -1159,6 +1290,10 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1159
1290
|
useFollowHook,
|
|
1160
1291
|
showBottomSheetForContext,
|
|
1161
1292
|
openAvatarPicker,
|
|
1293
|
+
accountDialogController,
|
|
1294
|
+
accountDialogOpen,
|
|
1295
|
+
openAccountDialog,
|
|
1296
|
+
closeAccountDialog,
|
|
1162
1297
|
accounts,
|
|
1163
1298
|
switchToAccount,
|
|
1164
1299
|
refreshAccounts,
|
|
@@ -1221,6 +1356,10 @@ const LOADING_STATE: OxyContextState = {
|
|
|
1221
1356
|
clientId: null,
|
|
1222
1357
|
oxyServices: LOADING_STATE_OXY_SERVICES,
|
|
1223
1358
|
openAvatarPicker: () => {},
|
|
1359
|
+
accountDialogController: null,
|
|
1360
|
+
isAccountDialogOpen: false,
|
|
1361
|
+
openAccountDialog: () => {},
|
|
1362
|
+
closeAccountDialog: () => {},
|
|
1224
1363
|
accounts: [],
|
|
1225
1364
|
switchToAccount: () => rejectMissingProvider<void>(),
|
|
1226
1365
|
refreshAccounts: () => rejectMissingProvider<void>(),
|
|
@@ -109,7 +109,7 @@ export const useUpdateProfile = () => {
|
|
|
109
109
|
refreshAvatarInStore(activeSessionId, updates.avatar, oxyServices);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
// Invalidate all related queries so every consumer (
|
|
112
|
+
// Invalidate all related queries so every consumer (the account dialog,
|
|
113
113
|
// session lists, managed accounts, etc.) refetches the fresh profile.
|
|
114
114
|
// This is critical right after `username` is set the first time, when
|
|
115
115
|
// every cached "session profile" still reports the user as unnamed.
|
package/src/ui/hooks/useAuth.ts
CHANGED
|
@@ -23,11 +23,10 @@
|
|
|
23
23
|
* - Manual sign-in: signIn() redirects to the IdP (web) or opens the auth sheet (native)
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { useCallback
|
|
26
|
+
import { useCallback } from 'react';
|
|
27
27
|
import { useOxy } from '../context/OxyContext';
|
|
28
28
|
import type { User } from '@oxyhq/core';
|
|
29
29
|
import { isWebBrowser } from '../utils/isWebBrowser';
|
|
30
|
-
import { showSignInModal } from '../components/SignInModal';
|
|
31
30
|
|
|
32
31
|
export interface AuthState {
|
|
33
32
|
/** Current authenticated user, null if not authenticated */
|
|
@@ -138,44 +137,33 @@ export function useAuth(): UseAuthReturn {
|
|
|
138
137
|
getPublicKey,
|
|
139
138
|
showBottomSheet,
|
|
140
139
|
openAvatarPicker,
|
|
140
|
+
openAccountDialog,
|
|
141
141
|
} = useOxy();
|
|
142
142
|
|
|
143
143
|
const signIn = useCallback(async (publicKey?: string): Promise<User> => {
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
// already restored a session if one existed; an explicit click presents the
|
|
147
|
-
// SDK sign-in surface (password / QR device flow / add account).
|
|
148
|
-
if (isWebBrowser() && !publicKey) {
|
|
149
|
-
showSignInModal();
|
|
150
|
-
// Resolves when the modal commits a session; the caller typically reacts
|
|
151
|
-
// to `isAuthenticated` rather than this promise.
|
|
152
|
-
return new Promise<User>(() => undefined);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Native: use the cryptographic identity directly when a public key is given.
|
|
144
|
+
// Native: sign in directly with the cryptographic identity when a public key
|
|
145
|
+
// is provided, or an existing keychain identity is found.
|
|
156
146
|
if (publicKey) {
|
|
157
147
|
return oxySignIn(publicKey);
|
|
158
148
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
149
|
+
if (!isWebBrowser()) {
|
|
150
|
+
const hasExisting = await hasIdentity();
|
|
151
|
+
if (hasExisting) {
|
|
152
|
+
const existingKey = await getPublicKey();
|
|
153
|
+
if (existingKey) {
|
|
154
|
+
return oxySignIn(existingKey);
|
|
155
|
+
}
|
|
166
156
|
}
|
|
167
157
|
}
|
|
168
158
|
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
throw new Error('No authentication method available');
|
|
178
|
-
}, [oxySignIn, hasIdentity, getPublicKey, showBottomSheet]);
|
|
159
|
+
// Web, or native without a keychain identity: open the unified account dialog
|
|
160
|
+
// on its sign-in view (device flow / QR / password hand-off). There is NO
|
|
161
|
+
// automatic navigation to a login page — the device-first cold boot already
|
|
162
|
+
// restored a session if one existed. The caller reacts to `isAuthenticated`,
|
|
163
|
+
// so this promise intentionally never resolves.
|
|
164
|
+
openAccountDialog('signin');
|
|
165
|
+
return new Promise<User>(() => undefined);
|
|
166
|
+
}, [oxySignIn, hasIdentity, getPublicKey, openAccountDialog]);
|
|
179
167
|
|
|
180
168
|
const signOut = useCallback(async (): Promise<void> => {
|
|
181
169
|
await logout();
|