@oxyhq/services 27.1.3 → 29.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/LICENSE +202 -661
- package/NOTICE +16 -0
- package/README.md +67 -2
- package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionModule.kt +178 -0
- package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionProvider.kt +99 -0
- package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionStore.kt +115 -0
- package/expo-module.config.json +1 -0
- package/lib/commonjs/index.js +78 -16
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/boot/runProviderColdBoot.js +7 -0
- package/lib/commonjs/ui/boot/runProviderColdBoot.js.map +1 -1
- package/lib/commonjs/ui/client.js +12 -7
- package/lib/commonjs/ui/client.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +10 -27
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAuthChooser.js +132 -44
- package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +4 -2
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/SurfaceScreen.js +31 -3
- package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +209 -84
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/SignInEntryView.js +25 -7
- package/lib/commonjs/ui/components/authChooser/SignInEntryView.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/primitives.js +35 -22
- package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/signInProgress.js +5 -0
- package/lib/commonjs/ui/components/authChooser/signInProgress.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/types.js +11 -0
- package/lib/commonjs/ui/components/authChooser/types.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +257 -306
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +27 -37
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/context/oxyContextHelpers.js +0 -29
- package/lib/commonjs/ui/context/oxyContextHelpers.js.map +1 -1
- package/lib/commonjs/ui/context/useOxyAccountGraph.js +6 -17
- package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
- package/lib/commonjs/ui/hooks/accountDialogSnapshot.js +42 -0
- package/lib/commonjs/ui/hooks/accountDialogSnapshot.js.map +1 -0
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +0 -19
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/commonjs/ui/hooks/useDeviceSwitcher.js +57 -0
- package/lib/commonjs/ui/hooks/useDeviceSwitcher.js.map +1 -0
- package/lib/commonjs/ui/hooks/useI18n.js +22 -3
- package/lib/commonjs/ui/hooks/useI18n.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +46 -153
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/commonjs/ui/index.js +12 -7
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/navigation/routes.js +85 -73
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaces.js +8 -7
- package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
- package/lib/commonjs/ui/runtime/createOxyRuntime.js +433 -0
- package/lib/commonjs/ui/runtime/createOxyRuntime.js.map +1 -0
- package/lib/commonjs/ui/runtime/index.js +63 -0
- package/lib/commonjs/ui/runtime/index.js.map +1 -0
- package/lib/commonjs/ui/runtime/runtimeContext.js +83 -0
- package/lib/commonjs/ui/runtime/runtimeContext.js.map +1 -0
- package/lib/commonjs/ui/runtime/types.js +6 -0
- package/lib/commonjs/ui/runtime/types.js.map +1 -0
- package/lib/commonjs/ui/runtime/useRuntimeSnapshot.js +57 -0
- package/lib/commonjs/ui/runtime/useRuntimeSnapshot.js.map +1 -0
- package/lib/commonjs/ui/screens/AccountMembersScreen.js +3 -4
- package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/CreateAccountScreen.js +3 -12
- package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +6 -5
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +4 -4
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +4 -2
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/server.js +1 -2
- package/lib/commonjs/ui/server.js.map +1 -1
- package/lib/commonjs/ui/session/authStore.js +45 -9
- package/lib/commonjs/ui/session/authStore.js.map +1 -1
- package/lib/commonjs/ui/session/sharedDeviceCredentialStore.js +306 -0
- package/lib/commonjs/ui/session/sharedDeviceCredentialStore.js.map +1 -0
- package/lib/commonjs/ui/stores/authStore.js +154 -55
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/stores/followTargetStore.js +27 -0
- package/lib/commonjs/ui/stores/followTargetStore.js.map +1 -1
- package/lib/commonjs/ui/utils/avatarUtils.js +2 -36
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/index.js +20 -9
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/boot/runProviderColdBoot.js +7 -0
- package/lib/module/ui/boot/runProviderColdBoot.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/OxyAccountDialogScreen.js +10 -27
- package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/module/ui/components/OxyAuthChooser.js +134 -44
- package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +5 -3
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/SurfaceScreen.js +33 -5
- package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/module/ui/components/authChooser/AccountsMenuView.js +210 -85
- package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/module/ui/components/authChooser/SignInEntryView.js +25 -7
- package/lib/module/ui/components/authChooser/SignInEntryView.js.map +1 -1
- package/lib/module/ui/components/authChooser/primitives.js +35 -22
- package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/module/ui/components/authChooser/signInProgress.js +5 -0
- package/lib/module/ui/components/authChooser/signInProgress.js.map +1 -1
- package/lib/module/ui/components/authChooser/types.js +11 -0
- package/lib/module/ui/components/authChooser/types.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +251 -303
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +27 -37
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/context/oxyContextHelpers.js +0 -28
- package/lib/module/ui/context/oxyContextHelpers.js.map +1 -1
- package/lib/module/ui/context/useOxyAccountGraph.js +6 -17
- package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
- package/lib/module/ui/hooks/accountDialogSnapshot.js +38 -0
- package/lib/module/ui/hooks/accountDialogSnapshot.js.map +1 -0
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +0 -19
- package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/module/ui/hooks/useDeviceSwitcher.js +53 -0
- package/lib/module/ui/hooks/useDeviceSwitcher.js.map +1 -0
- package/lib/module/ui/hooks/useI18n.js +24 -4
- package/lib/module/ui/hooks/useI18n.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +47 -155
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/module/ui/index.js +1 -2
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/navigation/routes.js +84 -72
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/navigation/surfaces.js +6 -6
- package/lib/module/ui/navigation/surfaces.js.map +1 -1
- package/lib/module/ui/runtime/createOxyRuntime.js +430 -0
- package/lib/module/ui/runtime/createOxyRuntime.js.map +1 -0
- package/lib/module/ui/runtime/index.js +15 -0
- package/lib/module/ui/runtime/index.js.map +1 -0
- package/lib/module/ui/runtime/runtimeContext.js +75 -0
- package/lib/module/ui/runtime/runtimeContext.js.map +1 -0
- package/lib/module/ui/runtime/types.js +4 -0
- package/lib/module/ui/runtime/types.js.map +1 -0
- package/lib/module/ui/runtime/useRuntimeSnapshot.js +52 -0
- package/lib/module/ui/runtime/useRuntimeSnapshot.js.map +1 -0
- package/lib/module/ui/screens/AccountMembersScreen.js +4 -5
- package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/module/ui/screens/CreateAccountScreen.js +4 -13
- package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js +6 -5
- package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +5 -5
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustRulesScreen.js +4 -2
- package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/module/ui/server.js +0 -1
- package/lib/module/ui/server.js.map +1 -1
- package/lib/module/ui/session/authStore.js +46 -11
- package/lib/module/ui/session/authStore.js.map +1 -1
- package/lib/module/ui/session/sharedDeviceCredentialStore.js +302 -0
- package/lib/module/ui/session/sharedDeviceCredentialStore.js.map +1 -0
- package/lib/module/ui/stores/authStore.js +154 -55
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/stores/followTargetStore.js +25 -0
- package/lib/module/ui/stores/followTargetStore.js.map +1 -1
- package/lib/module/ui/utils/avatarUtils.js +2 -35
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +6 -4
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/client.d.ts +1 -2
- package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts +11 -4
- package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts +3 -1
- package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +18 -6
- package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/signInProgress.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +33 -1
- package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +35 -4
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +8 -12
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/oxyContextHelpers.d.ts +0 -2
- package/lib/typescript/commonjs/ui/context/oxyContextHelpers.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +9 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts +1 -3
- package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts +15 -0
- package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts +49 -0
- package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useI18n.d.ts +13 -0
- package/lib/typescript/commonjs/ui/hooks/useI18n.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts +23 -18
- package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +1 -2
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +15 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/runtime/createOxyRuntime.d.ts +144 -0
- package/lib/typescript/commonjs/ui/runtime/createOxyRuntime.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/runtime/index.d.ts +16 -0
- package/lib/typescript/commonjs/ui/runtime/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/runtime/runtimeContext.d.ts +43 -0
- package/lib/typescript/commonjs/ui/runtime/runtimeContext.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/runtime/types.d.ts +89 -0
- package/lib/typescript/commonjs/ui/runtime/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/runtime/useRuntimeSnapshot.d.ts +23 -0
- package/lib/typescript/commonjs/ui/runtime/useRuntimeSnapshot.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/AccountMembersScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/server.d.ts +0 -1
- package/lib/typescript/commonjs/ui/server.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/authStore.d.ts +60 -9
- package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/sharedDeviceCredentialStore.d.ts +32 -0
- package/lib/typescript/commonjs/ui/session/sharedDeviceCredentialStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/stores/authStore.d.ts +49 -5
- package/lib/typescript/commonjs/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/stores/followTargetStore.d.ts +8 -1
- package/lib/typescript/commonjs/ui/stores/followTargetStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +26 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts +2 -10
- package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +6 -4
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +1 -2
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts +11 -4
- package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts +3 -1
- package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +18 -6
- package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/signInProgress.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/types.d.ts +33 -1
- package/lib/typescript/module/ui/components/authChooser/types.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts +35 -4
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +8 -12
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/oxyContextHelpers.d.ts +0 -2
- package/lib/typescript/module/ui/context/oxyContextHelpers.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +9 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts +1 -3
- package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts +15 -0
- package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts +49 -0
- package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useI18n.d.ts +13 -0
- package/lib/typescript/module/ui/hooks/useI18n.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts +23 -18
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +1 -2
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts +15 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/module/ui/runtime/createOxyRuntime.d.ts +144 -0
- package/lib/typescript/module/ui/runtime/createOxyRuntime.d.ts.map +1 -0
- package/lib/typescript/module/ui/runtime/index.d.ts +16 -0
- package/lib/typescript/module/ui/runtime/index.d.ts.map +1 -0
- package/lib/typescript/module/ui/runtime/runtimeContext.d.ts +43 -0
- package/lib/typescript/module/ui/runtime/runtimeContext.d.ts.map +1 -0
- package/lib/typescript/module/ui/runtime/types.d.ts +89 -0
- package/lib/typescript/module/ui/runtime/types.d.ts.map +1 -0
- package/lib/typescript/module/ui/runtime/useRuntimeSnapshot.d.ts +23 -0
- package/lib/typescript/module/ui/runtime/useRuntimeSnapshot.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/server.d.ts +0 -1
- package/lib/typescript/module/ui/server.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/authStore.d.ts +60 -9
- package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/sharedDeviceCredentialStore.d.ts +32 -0
- package/lib/typescript/module/ui/session/sharedDeviceCredentialStore.d.ts.map +1 -0
- package/lib/typescript/module/ui/stores/authStore.d.ts +49 -5
- package/lib/typescript/module/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/module/ui/stores/followTargetStore.d.ts +8 -1
- package/lib/typescript/module/ui/stores/followTargetStore.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +26 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/avatarUtils.d.ts +2 -10
- package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
- package/package.json +8 -8
- package/plugins/withSharedDeviceSessionProvider.js +102 -0
- package/plugins/withSharedDeviceSessionReader.js +57 -0
- package/src/__tests__/esmSourcePurity.test.ts +61 -0
- package/src/index.ts +36 -9
- package/src/ui/boot/runProviderColdBoot.ts +7 -0
- package/src/ui/client.ts +1 -2
- package/src/ui/components/OxyAccountDialogScreen.tsx +10 -29
- package/src/ui/components/OxyAuthChooser.tsx +149 -50
- package/src/ui/components/OxyProvider.tsx +7 -5
- package/src/ui/components/SurfaceScreen.tsx +28 -4
- package/src/ui/components/__tests__/followTargetButton.test.ts +39 -0
- package/src/ui/components/authChooser/AccountsMenuView.tsx +246 -96
- package/src/ui/components/authChooser/SignInEntryView.tsx +31 -8
- package/src/ui/components/authChooser/primitives.tsx +37 -23
- package/src/ui/components/authChooser/signInProgress.ts +4 -0
- package/src/ui/components/authChooser/types.ts +34 -1
- package/src/ui/context/OxyContext.tsx +269 -324
- package/src/ui/context/hooks/useAuthOperations.ts +32 -35
- package/src/ui/context/oxyContextHelpers.ts +0 -30
- package/src/ui/context/oxyContextTypes.ts +9 -1
- package/src/ui/context/useOxyAccountGraph.ts +5 -19
- package/src/ui/hooks/accountDialogSnapshot.ts +37 -0
- package/src/ui/hooks/mutations/useAccountMutations.ts +0 -19
- package/src/ui/hooks/queries/__tests__/userCache.test.ts +12 -1
- package/src/ui/hooks/useDeviceSwitcher.ts +110 -0
- package/src/ui/hooks/useI18n.ts +23 -3
- package/src/ui/hooks/useSessionManagement.ts +62 -211
- package/src/ui/index.ts +1 -2
- package/src/ui/navigation/routes.ts +85 -75
- package/src/ui/navigation/surfaces.ts +6 -9
- package/src/ui/runtime/createOxyRuntime.ts +623 -0
- package/src/ui/runtime/index.ts +34 -0
- package/src/ui/runtime/runtimeContext.tsx +111 -0
- package/src/ui/runtime/types.ts +110 -0
- package/src/ui/runtime/useRuntimeSnapshot.ts +52 -0
- package/src/ui/screens/AccountMembersScreen.tsx +6 -5
- package/src/ui/screens/CreateAccountScreen.tsx +3 -16
- package/src/ui/screens/trust/TrustCenterScreen.tsx +7 -7
- package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +4 -5
- package/src/ui/screens/trust/TrustRewardsScreen.tsx +1 -1
- package/src/ui/screens/trust/TrustRulesScreen.tsx +3 -2
- package/src/ui/server.ts +0 -1
- package/src/ui/session/__tests__/authStore.test.ts +90 -0
- package/src/ui/session/__tests__/sharedDeviceCredentialStore.test.ts +289 -0
- package/src/ui/session/authStore.ts +78 -9
- package/src/ui/session/sharedDeviceCredentialStore.ts +318 -0
- package/src/ui/stores/authStore.ts +171 -43
- package/src/ui/stores/followTargetStore.ts +24 -1
- package/src/ui/types/navigation.ts +26 -0
- package/src/ui/utils/avatarUtils.ts +2 -37
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +0 -64
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +0 -1
- package/lib/commonjs/ui/screens/trust/trustTier.js +0 -23
- package/lib/commonjs/ui/screens/trust/trustTier.js.map +0 -1
- package/lib/commonjs/ui/stores/accountStore.js +0 -221
- package/lib/commonjs/ui/stores/accountStore.js.map +0 -1
- package/lib/module/ui/hooks/useSwitchableAccounts.js +0 -60
- package/lib/module/ui/hooks/useSwitchableAccounts.js.map +0 -1
- package/lib/module/ui/screens/trust/trustTier.js +0 -19
- package/lib/module/ui/screens/trust/trustTier.js.map +0 -1
- package/lib/module/ui/stores/accountStore.js +0 -213
- package/lib/module/ui/stores/accountStore.js.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +0 -23
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts +0 -9
- package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/stores/accountStore.d.ts +0 -27
- package/lib/typescript/commonjs/ui/stores/accountStore.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +0 -23
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/trust/trustTier.d.ts +0 -9
- package/lib/typescript/module/ui/screens/trust/trustTier.d.ts.map +0 -1
- package/lib/typescript/module/ui/stores/accountStore.d.ts +0 -27
- package/lib/typescript/module/ui/stores/accountStore.d.ts.map +0 -1
- package/src/ui/hooks/useSwitchableAccounts.ts +0 -75
- package/src/ui/screens/trust/trustTier.ts +0 -20
- package/src/ui/stores/accountStore.ts +0 -264
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The platform half of the shared DeviceSession credential.
|
|
3
|
+
*
|
|
4
|
+
* `@oxyhq/core` owns and tests the RULES; what is pinned here is the mapping from
|
|
5
|
+
* each platform's failure shapes onto them — and that mapping is where the
|
|
6
|
+
* dangerous mistake lives. `expo-secure-store` returns `null` for a missing item
|
|
7
|
+
* and THROWS when the keychain refuses; the Android broker answers with an
|
|
8
|
+
* explicit status. Collapsing either failure into "absent" is what would let a
|
|
9
|
+
* locked device look like one that never had a session.
|
|
10
|
+
*/
|
|
11
|
+
import type { SharedDeviceCredentialStore } from '@oxyhq/core';
|
|
12
|
+
|
|
13
|
+
const CRED = { deviceId: 'dev-shared', deviceSecret: 'ds-shared' };
|
|
14
|
+
const STORAGE_KEY = 'oxy_shared_device_session_v1';
|
|
15
|
+
|
|
16
|
+
/** A minimal in-memory `expo-secure-store` that records the options it was given. */
|
|
17
|
+
function makeSecureStoreMock() {
|
|
18
|
+
const items = new Map<string, string>();
|
|
19
|
+
const calls: { key: string; options?: Record<string, unknown> }[] = [];
|
|
20
|
+
let readError: Error | null = null;
|
|
21
|
+
let writeError: Error | null = null;
|
|
22
|
+
/** When set, `setItemAsync` resolves but nothing lands — the phantom-write case. */
|
|
23
|
+
let swallowWrites = false;
|
|
24
|
+
return {
|
|
25
|
+
items,
|
|
26
|
+
calls,
|
|
27
|
+
setReadError: (error: Error | null) => {
|
|
28
|
+
readError = error;
|
|
29
|
+
},
|
|
30
|
+
setWriteError: (error: Error | null) => {
|
|
31
|
+
writeError = error;
|
|
32
|
+
},
|
|
33
|
+
setSwallowWrites: (value: boolean) => {
|
|
34
|
+
swallowWrites = value;
|
|
35
|
+
},
|
|
36
|
+
module: {
|
|
37
|
+
WHEN_UNLOCKED_THIS_DEVICE_ONLY: 3,
|
|
38
|
+
getItemAsync: async (key: string, options?: Record<string, unknown>) => {
|
|
39
|
+
calls.push({ key, options });
|
|
40
|
+
if (readError) {
|
|
41
|
+
throw readError;
|
|
42
|
+
}
|
|
43
|
+
return items.get(key) ?? null;
|
|
44
|
+
},
|
|
45
|
+
setItemAsync: async (key: string, value: string, options?: Record<string, unknown>) => {
|
|
46
|
+
calls.push({ key, options });
|
|
47
|
+
if (writeError) {
|
|
48
|
+
throw writeError;
|
|
49
|
+
}
|
|
50
|
+
if (!swallowWrites) {
|
|
51
|
+
items.set(key, value);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
deleteItemAsync: async (key: string, options?: Record<string, unknown>) => {
|
|
55
|
+
calls.push({ key, options });
|
|
56
|
+
items.delete(key);
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type BrokerModule = {
|
|
63
|
+
read(): Promise<unknown>;
|
|
64
|
+
write(deviceId: string, deviceSecret: string): Promise<boolean>;
|
|
65
|
+
clear(): Promise<void>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Load the module fresh, with `Platform.OS` set and both native seams mocked.
|
|
70
|
+
*
|
|
71
|
+
* Two things here are load-bearing and were each got wrong first:
|
|
72
|
+
*
|
|
73
|
+
* - `jest.resetModules()` + `require`, NOT `jest.isolateModules`. The module
|
|
74
|
+
* memoises its keychain and broker handles at module scope, so it must be
|
|
75
|
+
* re-required per case — and with `isolateModules` a mock factory registered
|
|
76
|
+
* in one block leaked into the next block's module, so a test's own mock was
|
|
77
|
+
* silently ignored and its assertions read the PREVIOUS test's store.
|
|
78
|
+
* - `Platform.OS` is set on the instance in the CURRENT registry. A reset hands
|
|
79
|
+
* out a fresh `react-native` mock whose `OS` is back to its `'web'` default,
|
|
80
|
+
* so mutating an instance captured earlier leaves the code under test on the
|
|
81
|
+
* web branch and every platform assertion passes vacuously.
|
|
82
|
+
*/
|
|
83
|
+
function loadStore(
|
|
84
|
+
os: 'ios' | 'android' | 'web',
|
|
85
|
+
seams: { secureStore?: ReturnType<typeof makeSecureStoreMock>; broker?: BrokerModule | null } = {},
|
|
86
|
+
): SharedDeviceCredentialStore | null {
|
|
87
|
+
jest.resetModules();
|
|
88
|
+
jest.doMock('expo-modules-core', () => ({
|
|
89
|
+
requireOptionalNativeModule: () => seams.broker ?? null,
|
|
90
|
+
requireNativeModule: () => {
|
|
91
|
+
throw new Error('not available');
|
|
92
|
+
},
|
|
93
|
+
}));
|
|
94
|
+
// NOT `{ virtual: true }`: a virtual mock is keyed to the directory of the
|
|
95
|
+
// file that declared it, so one declared here would be invisible to the module
|
|
96
|
+
// under test two directories up — it would silently keep resolving
|
|
97
|
+
// `unsupported`. `expo-secure-store` is installed in the workspace, so the
|
|
98
|
+
// ordinary mock registers against its real resolved path. With no mock given,
|
|
99
|
+
// model the module being ABSENT.
|
|
100
|
+
const secureStoreModule = seams.secureStore?.module;
|
|
101
|
+
jest.doMock('expo-secure-store', () => {
|
|
102
|
+
if (!secureStoreModule) {
|
|
103
|
+
throw new Error("Cannot find module 'expo-secure-store'");
|
|
104
|
+
}
|
|
105
|
+
return secureStoreModule;
|
|
106
|
+
});
|
|
107
|
+
const rn = require('react-native') as { Platform: { OS: string } };
|
|
108
|
+
rn.Platform.OS = os;
|
|
109
|
+
const mod = require('../sharedDeviceCredentialStore') as typeof import('../sharedDeviceCredentialStore');
|
|
110
|
+
return mod.createPlatformSharedDeviceCredentialStore();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
afterEach(() => {
|
|
114
|
+
jest.dontMock('expo-modules-core');
|
|
115
|
+
jest.dontMock('expo-secure-store');
|
|
116
|
+
jest.resetModules();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('createPlatformSharedDeviceCredentialStore', () => {
|
|
120
|
+
test('web has no shared slot at all', () => {
|
|
121
|
+
// Each web origin is its own device by design; there is nothing to join.
|
|
122
|
+
expect(loadStore('web')).toBeNull();
|
|
123
|
+
// Positive control: `null` must mean "web", not "the harness never reached
|
|
124
|
+
// the platform branch" — the failure mode this whole harness had once.
|
|
125
|
+
expect(loadStore('android', { broker: null })).not.toBeNull();
|
|
126
|
+
expect(loadStore('ios')).not.toBeNull();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('iOS uses the keychain, not the Android broker', async () => {
|
|
130
|
+
// The branch is on the platform because `expo-secure-store` LOADS on Android
|
|
131
|
+
// too — it would just ignore the access group and read a package-private
|
|
132
|
+
// item, which is indistinguishable from an empty shared slot.
|
|
133
|
+
const secureStore = makeSecureStoreMock();
|
|
134
|
+
const broker: BrokerModule = {
|
|
135
|
+
read: jest.fn(async () => ({ status: 'present', ...CRED })),
|
|
136
|
+
write: jest.fn(async () => true),
|
|
137
|
+
clear: jest.fn(async () => undefined),
|
|
138
|
+
};
|
|
139
|
+
const store = loadStore('ios', { secureStore, broker });
|
|
140
|
+
await store?.read();
|
|
141
|
+
expect(broker.read).not.toHaveBeenCalled();
|
|
142
|
+
expect(secureStore.calls.length).toBeGreaterThan(0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('Android uses the broker, not the keychain', async () => {
|
|
146
|
+
const secureStore = makeSecureStoreMock();
|
|
147
|
+
const broker: BrokerModule = {
|
|
148
|
+
read: jest.fn(async () => ({ status: 'absent' })),
|
|
149
|
+
write: jest.fn(async () => true),
|
|
150
|
+
clear: jest.fn(async () => undefined),
|
|
151
|
+
};
|
|
152
|
+
const store = loadStore('android', { secureStore, broker });
|
|
153
|
+
await expect(store?.read()).resolves.toEqual({ state: 'absent' });
|
|
154
|
+
expect(broker.read).toHaveBeenCalled();
|
|
155
|
+
expect(secureStore.calls).toHaveLength(0);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('iOS keychain-group slot', () => {
|
|
160
|
+
test('a missing item is absent; a THROWN read is unavailable', async () => {
|
|
161
|
+
const secureStore = makeSecureStoreMock();
|
|
162
|
+
const store = loadStore('ios', { secureStore });
|
|
163
|
+
|
|
164
|
+
await expect(store?.read()).resolves.toEqual({ state: 'absent' });
|
|
165
|
+
|
|
166
|
+
secureStore.setReadError(new Error('User interaction is not allowed'));
|
|
167
|
+
const locked = await store?.read();
|
|
168
|
+
// The pair that must never be confused. `absent` authorises seeding the slot.
|
|
169
|
+
expect(locked?.state).toBe('unavailable');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('an unparseable item is unavailable, never absent', async () => {
|
|
173
|
+
const secureStore = makeSecureStoreMock();
|
|
174
|
+
secureStore.items.set(STORAGE_KEY, 'not-json-at-all');
|
|
175
|
+
const store = loadStore('ios', { secureStore });
|
|
176
|
+
// Something IS stored. Reporting absent would authorise overwriting whatever
|
|
177
|
+
// a newer build put there.
|
|
178
|
+
expect((await store?.read())?.state).toBe('unavailable');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('reads and writes carry the dedicated service AND the access group', async () => {
|
|
182
|
+
const secureStore = makeSecureStoreMock();
|
|
183
|
+
const store = loadStore('ios', { secureStore });
|
|
184
|
+
await store?.publish(CRED);
|
|
185
|
+
|
|
186
|
+
// Without `keychainAccessGroup` the item is package-private and no sibling
|
|
187
|
+
// app can ever join. Without the dedicated `keychainService` it shares the
|
|
188
|
+
// legacy shared-IDENTITY namespace inside the group — the exact conflation
|
|
189
|
+
// this phase exists to end.
|
|
190
|
+
for (const call of secureStore.calls) {
|
|
191
|
+
expect(call.options).toMatchObject({
|
|
192
|
+
keychainService: 'oxy_device_session',
|
|
193
|
+
keychainAccessGroup: 'group.so.oxy.shared',
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
expect(secureStore.calls.length).toBeGreaterThan(0);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('the item is written device-only so it never rides an OS backup to a new handset', async () => {
|
|
200
|
+
const secureStore = makeSecureStoreMock();
|
|
201
|
+
const store = loadStore('ios', { secureStore });
|
|
202
|
+
await store?.publish(CRED);
|
|
203
|
+
const write = secureStore.calls.find((c) => c.options?.keychainAccessible !== undefined);
|
|
204
|
+
expect(write?.options?.keychainAccessible).toBe(secureStore.module.WHEN_UNLOCKED_THIS_DEVICE_ONLY);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('a publish round-trips and reads back as present', async () => {
|
|
208
|
+
const secureStore = makeSecureStoreMock();
|
|
209
|
+
const store = loadStore('ios', { secureStore });
|
|
210
|
+
await expect(store?.publish(CRED)).resolves.toBe(true);
|
|
211
|
+
await expect(store?.read()).resolves.toEqual({ state: 'present', credential: CRED });
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test('a write that silently does not land reports false', async () => {
|
|
215
|
+
// A keychain write can resolve without the item landing under the access
|
|
216
|
+
// group (a missing entitlement is the usual cause). A phantom credential
|
|
217
|
+
// would send a fresh install into a mint that can never succeed.
|
|
218
|
+
const secureStore = makeSecureStoreMock();
|
|
219
|
+
secureStore.setSwallowWrites(true);
|
|
220
|
+
const store = loadStore('ios', { secureStore });
|
|
221
|
+
await expect(store?.publish(CRED)).resolves.toBe(false);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('a throwing write reports false rather than propagating', async () => {
|
|
225
|
+
const secureStore = makeSecureStoreMock();
|
|
226
|
+
secureStore.setWriteError(new Error('keychain error -34018'));
|
|
227
|
+
const store = loadStore('ios', { secureStore });
|
|
228
|
+
await expect(store?.publish(CRED)).resolves.toBe(false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('the slot is unsupported when expo-secure-store is not installed', async () => {
|
|
232
|
+
const store = loadStore('ios');
|
|
233
|
+
// No `expo-secure-store` mock registered → the dynamic import rejects.
|
|
234
|
+
expect((await store?.read())?.state).toBe('unsupported');
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe('Android broker slot', () => {
|
|
239
|
+
test('narrows a present payload', async () => {
|
|
240
|
+
const store = loadStore('android', {
|
|
241
|
+
broker: { read: async () => ({ status: 'present', ...CRED }), write: async () => true, clear: async () => undefined },
|
|
242
|
+
});
|
|
243
|
+
await expect(store?.read()).resolves.toEqual({ state: 'present', credential: CRED });
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test('an explicit unavailable status stays unavailable', async () => {
|
|
247
|
+
const store = loadStore('android', {
|
|
248
|
+
broker: {
|
|
249
|
+
read: async () => ({ status: 'unavailable', reason: 'GeneralSecurityException' }),
|
|
250
|
+
write: async () => true,
|
|
251
|
+
clear: async () => undefined,
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
expect((await store?.read())?.state).toBe('unavailable');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('a THROWN broker call is unavailable, never absent', async () => {
|
|
258
|
+
const store = loadStore('android', {
|
|
259
|
+
broker: {
|
|
260
|
+
read: async () => {
|
|
261
|
+
throw new Error('binder transaction failed');
|
|
262
|
+
},
|
|
263
|
+
write: async () => true,
|
|
264
|
+
clear: async () => undefined,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
expect((await store?.read())?.state).toBe('unavailable');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test('an unrecognised payload from an older sibling is unavailable, never absent', async () => {
|
|
271
|
+
const store = loadStore('android', {
|
|
272
|
+
broker: { read: async () => ({ ok: true }), write: async () => true, clear: async () => undefined },
|
|
273
|
+
});
|
|
274
|
+
expect((await store?.read())?.state).toBe('unavailable');
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('the slot is unsupported when the native module is not linked', async () => {
|
|
278
|
+
const store = loadStore('android', { broker: null });
|
|
279
|
+
expect((await store?.read())?.state).toBe('unsupported');
|
|
280
|
+
await expect(store?.publish(CRED)).resolves.toBe(false);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test('publish forwards the broker’s own read-back verdict', async () => {
|
|
284
|
+
const unverified = loadStore('android', {
|
|
285
|
+
broker: { read: async () => ({ status: 'absent' }), write: async () => false, clear: async () => undefined },
|
|
286
|
+
});
|
|
287
|
+
await expect(unverified?.publish(CRED)).resolves.toBe(false);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
@@ -1,25 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Platform `AuthStateStore` for `@oxyhq/services`.
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `
|
|
9
|
-
* seam:
|
|
4
|
+
* The device model persists the durable device credential (`deviceId` +
|
|
5
|
+
* `deviceSecret`) per origin (web) / per device (native), and the SDK re-mints
|
|
6
|
+
* the access token from that credential on cold boot. `@oxyhq/core` owns the
|
|
7
|
+
* store shape + logic (`createWebAuthStateStore` / `createNativeAuthStateStore` /
|
|
8
|
+
* `createMemoryAuthStateStore`); this module only selects the seam:
|
|
10
9
|
*
|
|
10
|
+
* - `storage: 'ephemeral'` → `createMemoryAuthStateStore()`, on EVERY platform.
|
|
11
11
|
* - web → `createWebAuthStateStore()` (localStorage, in-memory fallback).
|
|
12
12
|
* - native → `createNativeAuthStateStore(secureKV)` for the SESSION blob over
|
|
13
13
|
* the shared `createNativeSecureKeyValueStorage()` adapter
|
|
14
|
-
* (`expo-secure-store`, AsyncStorage fallback)
|
|
14
|
+
* (`expo-secure-store`, AsyncStorage fallback), WRAPPED so every credential
|
|
15
|
+
* it persists is also mirrored into the device-wide shared slot.
|
|
16
|
+
*
|
|
17
|
+
* The native wrapper is how several official apps end up on ONE `DeviceSession`
|
|
18
|
+
* (and therefore one active context): whichever app proves a credential publishes
|
|
19
|
+
* it, and a later-installed sibling adopts it during cold boot instead of asking
|
|
20
|
+
* for the Commons identity key. The mirror is additive — it can neither change
|
|
21
|
+
* nor fail the app's own durable write.
|
|
15
22
|
*/
|
|
16
23
|
import {
|
|
17
24
|
createWebAuthStateStore,
|
|
18
25
|
createNativeAuthStateStore,
|
|
26
|
+
createMemoryAuthStateStore,
|
|
27
|
+
createSharedMirroringAuthStateStore,
|
|
19
28
|
type AuthStateStore,
|
|
29
|
+
type SessionMode,
|
|
20
30
|
} from '@oxyhq/core';
|
|
21
31
|
import { isReactNative } from '../utils/storageHelpers';
|
|
22
32
|
import { createNativeSecureKeyValueStorage } from './nativeSecureStorage';
|
|
33
|
+
import { createPlatformSharedDeviceCredentialStore } from './sharedDeviceCredentialStore';
|
|
34
|
+
|
|
35
|
+
export interface PlatformAuthStateStoreOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Who owns the session this provider resolves. Only `'account'` mirrors into
|
|
38
|
+
* the device-wide shared slot.
|
|
39
|
+
*
|
|
40
|
+
* `'identity'` (the vault) is deliberately excluded, which keeps its storage
|
|
41
|
+
* behaviour byte-for-byte what it is today. The vault's credential is a
|
|
42
|
+
* perfectly valid device credential, so publishing it would arguably be
|
|
43
|
+
* correct — but it would also let every ordinary app on the device join the
|
|
44
|
+
* vault's device session as a side effect of the vault persisting a token, and
|
|
45
|
+
* "a background write changes which session five other apps boot into" is not
|
|
46
|
+
* a decision a storage seam gets to make.
|
|
47
|
+
*/
|
|
48
|
+
sessionMode?: SessionMode;
|
|
49
|
+
/**
|
|
50
|
+
* Whether this origin/app may persist a durable device credential AT ALL.
|
|
51
|
+
*
|
|
52
|
+
* `'ephemeral'` stores nothing durable and mirrors nothing: the session lives
|
|
53
|
+
* in memory for the lifetime of the page and is gone on reload. Its one caller
|
|
54
|
+
* is `auth.oxy.so` with the browser hub enabled (issue #937 Phase 5, ADR 0003),
|
|
55
|
+
* where the durable credential for the browser profile is the server-side
|
|
56
|
+
* DeviceSession behind the `__Host-oxy-device` handle.
|
|
57
|
+
*
|
|
58
|
+
* See `OxyProviderProps.deviceCredentialStorage` for why the answer to "let the
|
|
59
|
+
* hub be authoritative" is to stop persisting the other credential rather than
|
|
60
|
+
* to consult it second.
|
|
61
|
+
*/
|
|
62
|
+
storage?: 'persistent' | 'ephemeral';
|
|
63
|
+
}
|
|
23
64
|
|
|
24
65
|
/**
|
|
25
66
|
* Build the platform {@link AuthStateStore} for this runtime.
|
|
@@ -27,11 +68,39 @@ import { createNativeSecureKeyValueStorage } from './nativeSecureStorage';
|
|
|
27
68
|
* Native persists the SESSION blob (`deviceId` + `deviceSecret` + cached access
|
|
28
69
|
* token) per-app in SecureStore; the SDK re-mints the access token from the
|
|
29
70
|
* device credential on the next cold boot.
|
|
71
|
+
*
|
|
72
|
+
* ## The ephemeral check is FIRST, and the order is load-bearing
|
|
73
|
+
*
|
|
74
|
+
* It short-circuits above the `isReactNative()` branch so an ephemeral caller can
|
|
75
|
+
* never reach the native path — and therefore can never reach the shared-slot
|
|
76
|
+
* mirroring wrapper. Checked after that branch instead, an origin that has
|
|
77
|
+
* declined to persist a credential would publish one into the device-wide slot
|
|
78
|
+
* every sibling app adopts on cold boot: it would keep nothing itself while
|
|
79
|
+
* deciding which session five other apps boot into.
|
|
80
|
+
*
|
|
81
|
+
* That is unreachable today because the only ephemeral caller is a web origin, so
|
|
82
|
+
* `isReactNative()` is false there anyway. Unreachable today is exactly the kind
|
|
83
|
+
* of guarantee that stops holding when someone adds the second caller, so it is
|
|
84
|
+
* structural here rather than incidental, and
|
|
85
|
+
* `__tests__/session/authStoreEphemeral.test.ts` holds the ordering directly.
|
|
30
86
|
*/
|
|
31
|
-
export function createPlatformAuthStateStore(
|
|
87
|
+
export function createPlatformAuthStateStore(
|
|
88
|
+
options: PlatformAuthStateStoreOptions = {},
|
|
89
|
+
): AuthStateStore {
|
|
90
|
+
// FIRST, above every platform branch — see the docblock for why the ordering
|
|
91
|
+
// is the guarantee and not a coincidence.
|
|
92
|
+
if (options.storage === 'ephemeral') {
|
|
93
|
+
return createMemoryAuthStateStore();
|
|
94
|
+
}
|
|
95
|
+
|
|
32
96
|
if (!isReactNative()) {
|
|
33
97
|
return createWebAuthStateStore();
|
|
34
98
|
}
|
|
35
99
|
|
|
36
|
-
|
|
100
|
+
const local = createNativeAuthStateStore(createNativeSecureKeyValueStorage());
|
|
101
|
+
if (options.sessionMode === 'identity') {
|
|
102
|
+
return local;
|
|
103
|
+
}
|
|
104
|
+
const shared = createPlatformSharedDeviceCredentialStore();
|
|
105
|
+
return shared ? createSharedMirroringAuthStateStore({ local, shared }) : local;
|
|
37
106
|
}
|