@oxyhq/services 28.0.0 → 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/NOTICE +10 -9
- package/README.md +65 -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 +60 -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/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/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/utils/avatarUtils.js +2 -36
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/index.js +16 -8
- 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/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/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/utils/avatarUtils.js +2 -35
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +5 -3
- 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/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/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/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 +5 -3
- 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/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/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/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 +6 -7
- package/plugins/withSharedDeviceSessionProvider.js +102 -0
- package/plugins/withSharedDeviceSessionReader.js +57 -0
- package/src/__tests__/esmSourcePurity.test.ts +61 -0
- package/src/index.ts +31 -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/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/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/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/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/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/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/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/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/stores/accountStore.ts +0 -264
package/NOTICE
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
============================================================================
|
|
2
2
|
NOTICE
|
|
3
3
|
@oxyhq/services
|
|
4
|
-
Copyright (c) 2025-present The Oxy Collective Inc
|
|
5
|
-
|
|
4
|
+
Copyright (c) 2025-present The Oxy Collective, Inc.
|
|
5
|
+
============================================================================
|
|
6
6
|
|
|
7
|
-
This product is licensed under the Apache License, Version 2.0.
|
|
8
|
-
|
|
7
|
+
This product is licensed under the Apache License, Version 2.0. See the
|
|
8
|
+
LICENSE file in this directory.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
----------------------------------------------------------------------------
|
|
11
11
|
THIRD PARTY COMPONENTS
|
|
12
|
-
|
|
12
|
+
----------------------------------------------------------------------------
|
|
13
13
|
|
|
14
|
-
This package contains no third party source. Its dependencies are resolved
|
|
15
|
-
installed by the package manager and remain governed by their own
|
|
14
|
+
This package contains no third party source. Its dependencies are resolved
|
|
15
|
+
and installed by the package manager and remain governed by their own
|
|
16
|
+
licenses.
|
package/README.md
CHANGED
|
@@ -50,6 +50,69 @@ This package (`@oxyhq/services`) is the **single UI SDK** for every React surfac
|
|
|
50
50
|
|
|
51
51
|
See [PLATFORM_GUIDE.md](./PLATFORM_GUIDE.md) for the complete architecture guide.
|
|
52
52
|
|
|
53
|
+
### This package does not declare `sideEffects: false`
|
|
54
|
+
|
|
55
|
+
It used to, and the declaration was **wrong**. Three modules in the build have
|
|
56
|
+
top-level side effects, one of them the entry itself:
|
|
57
|
+
|
|
58
|
+
| Module | Effect |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `lib/module/index.js` | `setPlatformOS(Platform.OS)` — configures `@oxyhq/core` |
|
|
61
|
+
| `lib/module/ui/navigation/surfaceBackBridge.js` | `installEscapeHandler()` — installs a global key handler |
|
|
62
|
+
| `lib/module/ui/components/SettingsIcon.js` | assigns `displayName` |
|
|
63
|
+
|
|
64
|
+
Removing a false declaration would be worth doing on its own. It also fixed a
|
|
65
|
+
production outage, and that is the part worth remembering, because the symptom
|
|
66
|
+
looked nothing like a `package.json` field.
|
|
67
|
+
|
|
68
|
+
`auth.oxy.so/authorize` rendered a blank page with React error #130 ("element
|
|
69
|
+
type is undefined") for every request that reached `OxySignInRequestSurface`,
|
|
70
|
+
which blocked every OIDC login into Allo ([#784]). Source and dev server were
|
|
71
|
+
fine; only the production bundle was broken. Two facts combined:
|
|
72
|
+
|
|
73
|
+
1. **The UI graph was one large import cycle.** `ui/context/OxyContext` reaches
|
|
74
|
+
`ui/navigation/bottomSheetManager` → `navigation/routes`, `routes` reached
|
|
75
|
+
every screen (through `require()` calls it made for Metro's benefit), and
|
|
76
|
+
every screen reaches back into the context — a 67-module strongly connected
|
|
77
|
+
component that included `OxySignInRequestSurface`. A bundler cannot
|
|
78
|
+
concatenate a cycle, so it emits each member as a lazily-initialized wrapper
|
|
79
|
+
whose exported bindings are `undefined` until the initializer runs. Modules
|
|
80
|
+
outside the cycle, `OxyConsentScreen` among them, are emitted inline and were
|
|
81
|
+
never affected — which is exactly why only some screens broke.
|
|
82
|
+
2. **`sideEffects: false` told the bundler that running those initializers was
|
|
83
|
+
unobservable**, so rolldown-vite omitted the initializer call at the
|
|
84
|
+
consuming import site in `packages/auth` while still emitting the reference.
|
|
85
|
+
The binding was therefore never assigned, and React was handed `undefined`.
|
|
86
|
+
|
|
87
|
+
That cycle was the deeper defect, and it has since been cut down. `routes.ts`
|
|
88
|
+
registers screens as `lazy(() => import(...))` rather than `require()`, so the
|
|
89
|
+
registry no longer drags all 40 screens into the context's component; the two
|
|
90
|
+
remaining `require()` sites became static imports read at call time. Measured on
|
|
91
|
+
the built ESM output, the largest strongly connected component went from **67
|
|
92
|
+
modules to 2**, and `OxySignInRequestSurface` is no longer inside any cycle.
|
|
93
|
+
What is left is two mutual pairs — `surfaces` ↔ `SurfaceScreen` and
|
|
94
|
+
`OxyContext` ↔ `useFollow` — each of which only ever reads the other at call or
|
|
95
|
+
render time.
|
|
96
|
+
|
|
97
|
+
Cycles still exist, so do not re-add `sideEffects` in any form. A narrowed,
|
|
98
|
+
truthful list would leave every component still in a cycle exactly as exposed,
|
|
99
|
+
because none of *them* has a top-level side effect either. The cost of not
|
|
100
|
+
declaring it was measured at the time on the IdP's own production bundle, which
|
|
101
|
+
is the heaviest consumer of this package on the web: **5,483.86 kB → 5,489.99 kB
|
|
102
|
+
raw (+0.11%)** and **1,457.31 kB → 1,458.66 kB gzip (+0.09%)**.
|
|
103
|
+
|
|
104
|
+
**No module in this package's source may call `require()`.** The build is ESM,
|
|
105
|
+
and a surviving `require()` puts bundlers back into CommonJS interop — the same
|
|
106
|
+
lazily-initialized wrappers, reachable the same silent way. To defer a read, use
|
|
107
|
+
a thunk over a static import; to defer a *load*, use `import()`.
|
|
108
|
+
`src/__tests__/esmSourcePurity.test.ts` enforces this.
|
|
109
|
+
|
|
110
|
+
`packages/auth/lib/__tests__/authorize-surface-bundle.test.ts` builds the IdP's
|
|
111
|
+
real production bundle and renders the surface out of it, so a regression fails
|
|
112
|
+
in CI with React's own message instead of on auth.oxy.so.
|
|
113
|
+
|
|
114
|
+
[#784]: https://github.com/OxyHQ/OxyHQServices/issues/784
|
|
115
|
+
|
|
53
116
|
## Installation
|
|
54
117
|
|
|
55
118
|
```bash
|
|
@@ -618,7 +681,7 @@ const metadata = getLanguageMetadata('es-ES');
|
|
|
618
681
|
|
|
619
682
|
### Common Issues
|
|
620
683
|
|
|
621
|
-
#### 1. "useOxy
|
|
684
|
+
#### 1. "useOxy() was called outside <OxyProvider>"
|
|
622
685
|
|
|
623
686
|
**Solution**: Wrap your app with `OxyProvider`
|
|
624
687
|
|
|
@@ -785,6 +848,6 @@ Comprehensive documentation is available in the `/docs` directory:
|
|
|
785
848
|
|
|
786
849
|
## License
|
|
787
850
|
|
|
788
|
-
This package is licensed under the Apache License, Version 2.0, (c) The Oxy Collective Inc. See the [LICENSE](LICENSE) and [NOTICE](NOTICE) files for details.
|
|
851
|
+
This package is licensed under the Apache License, Version 2.0, (c) The Oxy Collective, Inc. See the [LICENSE](LICENSE) and [NOTICE](NOTICE) files for details.
|
|
789
852
|
|
|
790
853
|
Versions published before `28.0.0` were AGPL-3.0-only and stay that way; a licence change binds future versions only.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
package so.oxy.devicesession
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.net.Uri
|
|
5
|
+
import android.os.Bundle
|
|
6
|
+
import expo.modules.kotlin.exception.Exceptions
|
|
7
|
+
import expo.modules.kotlin.modules.Module
|
|
8
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* JS bridge for the shared DeviceSession credential.
|
|
12
|
+
*
|
|
13
|
+
* - `read` resolves the credential this DEVICE holds, from the sibling providers
|
|
14
|
+
* first and this app's own store second (see [readShared] for why that order).
|
|
15
|
+
* - `write` publishes into this app's own store only, and reports whether a
|
|
16
|
+
* read-back confirmed it.
|
|
17
|
+
* - `clear` drops this app's copy.
|
|
18
|
+
*
|
|
19
|
+
* ## `read` returns a STATUS, not a nullable value
|
|
20
|
+
*
|
|
21
|
+
* The three answers "here it is", "there is none" and "I could not tell" are
|
|
22
|
+
* genuinely different, and only the second one authorises the JS side to seed the
|
|
23
|
+
* slot. A nullable return would merge the last two, and the merged value reads as
|
|
24
|
+
* "fresh device" — which is exactly how a locked or broken keystore ends up
|
|
25
|
+
* overwriting a live session. So every path here reports its status explicitly,
|
|
26
|
+
* and never degrades a failure into an absence.
|
|
27
|
+
*
|
|
28
|
+
* Return shapes:
|
|
29
|
+
* ```
|
|
30
|
+
* { "status": "present", "deviceId": "...", "deviceSecret": "..." }
|
|
31
|
+
* { "status": "absent" }
|
|
32
|
+
* { "status": "unavailable", "reason": "<ExceptionClassName>" }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Plain scalars in, a plain `Map` out — never an Expo `Record`. This package
|
|
36
|
+
* ships as SOURCE that each consuming app compiles, so the annotation processing
|
|
37
|
+
* a `Record` needs to become introspectable does not necessarily run in the
|
|
38
|
+
* consumer's build; the one `Record` this package ever had failed to convert on a
|
|
39
|
+
* real device and stored nothing, silently. See the long note in
|
|
40
|
+
* `so.oxy.session.OxyBackgroundSessionModule` before reaching for one here.
|
|
41
|
+
*/
|
|
42
|
+
class OxyDeviceSessionModule : Module() {
|
|
43
|
+
private val context: Context
|
|
44
|
+
get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
|
|
45
|
+
|
|
46
|
+
override fun definition() = ModuleDefinition {
|
|
47
|
+
Name("OxyDeviceSession")
|
|
48
|
+
|
|
49
|
+
AsyncFunction("read") {
|
|
50
|
+
readShared()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
AsyncFunction("write") { deviceId: String, deviceSecret: String ->
|
|
54
|
+
if (deviceId.isEmpty() || deviceSecret.isEmpty()) {
|
|
55
|
+
return@AsyncFunction false
|
|
56
|
+
}
|
|
57
|
+
OxyDeviceSessionStore.write(context, deviceId, deviceSecret)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
AsyncFunction("clear") {
|
|
61
|
+
OxyDeviceSessionStore.clear(context)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Providers FIRST, this app's own store second.
|
|
67
|
+
*
|
|
68
|
+
* Under `android:sharedUserId="so.oxy.shared"` every Oxy app sees one data
|
|
69
|
+
* directory, so for a UID member the local file IS the group's file and the
|
|
70
|
+
* order changes nothing. It matters for a same-signature app OUTSIDE the UID:
|
|
71
|
+
* there the local file is a private mirror of whatever that app itself last
|
|
72
|
+
* wrote, so reading it first would shadow the group's real credential forever.
|
|
73
|
+
*
|
|
74
|
+
* `unavailable` is sticky across the whole sweep: if ANY source could not be
|
|
75
|
+
* read and none produced a credential, the answer is `unavailable`, not
|
|
76
|
+
* `absent`. The pessimistic merge is the point — the optimistic one authorises
|
|
77
|
+
* a write.
|
|
78
|
+
*/
|
|
79
|
+
private fun readShared(): Map<String, String> {
|
|
80
|
+
var unavailableReason: String? = null
|
|
81
|
+
|
|
82
|
+
for (authority in PROVIDER_AUTHORITIES) {
|
|
83
|
+
when (val read = callProvider(authority)) {
|
|
84
|
+
is DeviceSessionRead.Present -> return present(read)
|
|
85
|
+
is DeviceSessionRead.Unavailable -> unavailableReason = unavailableReason ?: read.reason
|
|
86
|
+
// Absent, or no provider there at all (not installed, refused, threw) —
|
|
87
|
+
// neither is evidence about the other sources, so keep looking.
|
|
88
|
+
else -> Unit
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
when (val local = OxyDeviceSessionStore.read(context)) {
|
|
93
|
+
is DeviceSessionRead.Present -> return present(local)
|
|
94
|
+
is DeviceSessionRead.Unavailable -> unavailableReason = unavailableReason ?: local.reason
|
|
95
|
+
is DeviceSessionRead.Absent -> Unit
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
val reason = unavailableReason
|
|
99
|
+
return if (reason != null) {
|
|
100
|
+
mapOf(
|
|
101
|
+
OxyDeviceSessionProvider.KEY_STATUS to OxyDeviceSessionProvider.STATUS_UNAVAILABLE,
|
|
102
|
+
OxyDeviceSessionProvider.KEY_REASON to reason,
|
|
103
|
+
)
|
|
104
|
+
} else {
|
|
105
|
+
mapOf(OxyDeviceSessionProvider.KEY_STATUS to OxyDeviceSessionProvider.STATUS_ABSENT)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private fun present(read: DeviceSessionRead.Present): Map<String, String> = mapOf(
|
|
110
|
+
OxyDeviceSessionProvider.KEY_STATUS to OxyDeviceSessionProvider.STATUS_PRESENT,
|
|
111
|
+
OxyDeviceSessionStore.KEY_DEVICE_ID to read.deviceId,
|
|
112
|
+
OxyDeviceSessionStore.KEY_DEVICE_SECRET to read.deviceSecret,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Call one sibling provider. `null` means "nothing to learn from this one" —
|
|
117
|
+
* the app is not installed, package visibility hid it, the permission was
|
|
118
|
+
* refused, or the call threw. A provider that answered but could not read its
|
|
119
|
+
* own store returns [DeviceSessionRead.Unavailable], which the sweep keeps.
|
|
120
|
+
*/
|
|
121
|
+
private fun callProvider(authority: String): DeviceSessionRead? = runCatching {
|
|
122
|
+
val uri = Uri.parse("content://$authority")
|
|
123
|
+
val bundle: Bundle = context.contentResolver.call(
|
|
124
|
+
uri,
|
|
125
|
+
OxyDeviceSessionProvider.METHOD_READ,
|
|
126
|
+
null,
|
|
127
|
+
null,
|
|
128
|
+
) ?: return@runCatching null
|
|
129
|
+
|
|
130
|
+
when (bundle.getString(OxyDeviceSessionProvider.KEY_STATUS)) {
|
|
131
|
+
OxyDeviceSessionProvider.STATUS_PRESENT -> {
|
|
132
|
+
val deviceId = bundle.getString(OxyDeviceSessionStore.KEY_DEVICE_ID)
|
|
133
|
+
val deviceSecret = bundle.getString(OxyDeviceSessionStore.KEY_DEVICE_SECRET)
|
|
134
|
+
if (deviceId.isNullOrEmpty() || deviceSecret.isNullOrEmpty()) {
|
|
135
|
+
// A `present` verdict with an incomplete payload is a broken peer, not
|
|
136
|
+
// an empty device.
|
|
137
|
+
DeviceSessionRead.Unavailable("IncompleteProviderPayload")
|
|
138
|
+
} else {
|
|
139
|
+
DeviceSessionRead.Present(deviceId, deviceSecret)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
OxyDeviceSessionProvider.STATUS_ABSENT -> DeviceSessionRead.Absent
|
|
143
|
+
OxyDeviceSessionProvider.STATUS_UNAVAILABLE ->
|
|
144
|
+
DeviceSessionRead.Unavailable(
|
|
145
|
+
bundle.getString(OxyDeviceSessionProvider.KEY_REASON) ?: "PeerUnavailable",
|
|
146
|
+
)
|
|
147
|
+
// An older sibling that predates this protocol. It said something we do not
|
|
148
|
+
// understand, so we have learned nothing — never read that as "absent".
|
|
149
|
+
else -> DeviceSessionRead.Unavailable("UnrecognisedProviderStatus")
|
|
150
|
+
}
|
|
151
|
+
}.getOrNull()
|
|
152
|
+
|
|
153
|
+
companion object {
|
|
154
|
+
/**
|
|
155
|
+
* Sibling authorities to sweep, in order. Each official Oxy Android app hosts
|
|
156
|
+
* the provider at `${applicationId}.devicesession` via the
|
|
157
|
+
* `withSharedDeviceSession` config plugin, and both the prod and `.dev`
|
|
158
|
+
* variants are listed so a developer build can join a device too.
|
|
159
|
+
*
|
|
160
|
+
* MAINTAINED LIST, and the constraint on it is specific: every entry must be
|
|
161
|
+
* an app inside the `so.oxy.shared` UID. UID members all serve ONE file, so
|
|
162
|
+
* the sweep is deterministic no matter which of them answers first. Adding an
|
|
163
|
+
* app that is same-signature but NOT in the UID would put a second,
|
|
164
|
+
* independent copy of "the shared credential" into the sweep and make the
|
|
165
|
+
* winner depend on list order.
|
|
166
|
+
*
|
|
167
|
+
* The same authorities must also be added to the `<queries>` block in
|
|
168
|
+
* `withSharedDeviceSession.js`, or Android 11+ package-visibility filtering
|
|
169
|
+
* hides them from `ContentResolver.call` and the sweep silently finds nothing.
|
|
170
|
+
*/
|
|
171
|
+
private val PROVIDER_AUTHORITIES = listOf(
|
|
172
|
+
"so.oxy.accounts.devicesession",
|
|
173
|
+
"so.oxy.accounts.dev.devicesession",
|
|
174
|
+
"so.oxy.commons.devicesession",
|
|
175
|
+
"so.oxy.commons.dev.devicesession",
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
package so.oxy.devicesession
|
|
2
|
+
|
|
3
|
+
import android.content.ContentProvider
|
|
4
|
+
import android.content.ContentValues
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.pm.PackageManager
|
|
7
|
+
import android.database.Cursor
|
|
8
|
+
import android.net.Uri
|
|
9
|
+
import android.os.Bundle
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Cross-process READ surface for the shared DeviceSession credential, declared
|
|
13
|
+
* per-app by the `withSharedDeviceSession` config plugin at authority
|
|
14
|
+
* `${applicationId}.devicesession` behind a `signature`-level permission.
|
|
15
|
+
*
|
|
16
|
+
* The signature check below is belt-and-suspenders on top of that permission:
|
|
17
|
+
* even if the manifest gate were ever misconfigured, a differently-signed caller
|
|
18
|
+
* still gets nothing. Same-signature is the whole trust boundary — an
|
|
19
|
+
* incorrectly-signed app cannot read this slot, and there is no other way in.
|
|
20
|
+
*
|
|
21
|
+
* READ-ONLY across the process boundary, deliberately. A caller may join the
|
|
22
|
+
* device's session; it may not seed or overwrite another app's. Writes happen
|
|
23
|
+
* only in-process via [OxyDeviceSessionModule], against this app's own store.
|
|
24
|
+
*
|
|
25
|
+
* What crosses the boundary is a session credential — never the identity
|
|
26
|
+
* keypair, which lives behind `so.oxy.identity.OxyIdentityProvider` under a
|
|
27
|
+
* different permission. That separation is the point.
|
|
28
|
+
*
|
|
29
|
+
* All standard CRUD operations are no-ops; this provider exists solely for the
|
|
30
|
+
* `call()` channel.
|
|
31
|
+
*/
|
|
32
|
+
class OxyDeviceSessionProvider : ContentProvider() {
|
|
33
|
+
override fun onCreate(): Boolean = true
|
|
34
|
+
|
|
35
|
+
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
|
|
36
|
+
if (method != METHOD_READ) return null
|
|
37
|
+
val ctx = context ?: return null
|
|
38
|
+
if (!callerSignatureMatches(ctx)) return null
|
|
39
|
+
|
|
40
|
+
return when (val read = OxyDeviceSessionStore.read(ctx)) {
|
|
41
|
+
is DeviceSessionRead.Present -> Bundle().apply {
|
|
42
|
+
putString(KEY_STATUS, STATUS_PRESENT)
|
|
43
|
+
putString(OxyDeviceSessionStore.KEY_DEVICE_ID, read.deviceId)
|
|
44
|
+
putString(OxyDeviceSessionStore.KEY_DEVICE_SECRET, read.deviceSecret)
|
|
45
|
+
}
|
|
46
|
+
is DeviceSessionRead.Absent -> Bundle().apply { putString(KEY_STATUS, STATUS_ABSENT) }
|
|
47
|
+
// Reported, not swallowed. A null here would be indistinguishable from
|
|
48
|
+
// "this app has no credential", and the caller would go on to treat the
|
|
49
|
+
// device as fresh.
|
|
50
|
+
is DeviceSessionRead.Unavailable -> Bundle().apply {
|
|
51
|
+
putString(KEY_STATUS, STATUS_UNAVAILABLE)
|
|
52
|
+
putString(KEY_REASON, read.reason)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* True when the calling package shares this app's signing certificate. Uses
|
|
59
|
+
* `checkSignatures` (deprecated but still the simplest correct cross-package
|
|
60
|
+
* signature comparison; returns SIGNATURE_MATCH only for same-cert apps).
|
|
61
|
+
*/
|
|
62
|
+
private fun callerSignatureMatches(ctx: Context): Boolean {
|
|
63
|
+
val caller = callingPackage ?: return false
|
|
64
|
+
return runCatching {
|
|
65
|
+
@Suppress("DEPRECATION")
|
|
66
|
+
ctx.packageManager.checkSignatures(caller, ctx.packageName) == PackageManager.SIGNATURE_MATCH
|
|
67
|
+
}.getOrDefault(false)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
override fun query(
|
|
71
|
+
uri: Uri,
|
|
72
|
+
projection: Array<out String>?,
|
|
73
|
+
selection: String?,
|
|
74
|
+
selectionArgs: Array<out String>?,
|
|
75
|
+
sortOrder: String?
|
|
76
|
+
): Cursor? = null
|
|
77
|
+
|
|
78
|
+
override fun getType(uri: Uri): String? = null
|
|
79
|
+
|
|
80
|
+
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
|
|
81
|
+
|
|
82
|
+
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
|
|
83
|
+
|
|
84
|
+
override fun update(
|
|
85
|
+
uri: Uri,
|
|
86
|
+
values: ContentValues?,
|
|
87
|
+
selection: String?,
|
|
88
|
+
selectionArgs: Array<out String>?
|
|
89
|
+
): Int = 0
|
|
90
|
+
|
|
91
|
+
companion object {
|
|
92
|
+
const val METHOD_READ = "read"
|
|
93
|
+
const val KEY_STATUS = "status"
|
|
94
|
+
const val KEY_REASON = "reason"
|
|
95
|
+
const val STATUS_PRESENT = "present"
|
|
96
|
+
const val STATUS_ABSENT = "absent"
|
|
97
|
+
const val STATUS_UNAVAILABLE = "unavailable"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
package so.oxy.devicesession
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.SharedPreferences
|
|
5
|
+
import so.oxy.storage.OxyEncryptedPrefs
|
|
6
|
+
import so.oxy.storage.RecoveryPolicy
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* What a read of the shared slot found.
|
|
10
|
+
*
|
|
11
|
+
* THREE outcomes, and the difference between the last two is the entire safety
|
|
12
|
+
* property of this file. An EMPTY slot authorises a write (seed the device
|
|
13
|
+
* session); a slot that could not be READ must authorise nothing, because it may
|
|
14
|
+
* hold a live session belonging to someone still signed in. Collapsing them —
|
|
15
|
+
* which a plain nullable return would do — is how a locked or broken keystore
|
|
16
|
+
* gets mistaken for a fresh device.
|
|
17
|
+
*/
|
|
18
|
+
internal sealed interface DeviceSessionRead {
|
|
19
|
+
data class Present(val deviceId: String, val deviceSecret: String) : DeviceSessionRead
|
|
20
|
+
object Absent : DeviceSessionRead
|
|
21
|
+
/** [reason] is an exception CLASS NAME only — never a message, never a value. */
|
|
22
|
+
data class Unavailable(val reason: String) : DeviceSessionRead
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The cross-app DeviceSession credential — `deviceId` + `deviceSecret`, and
|
|
27
|
+
* nothing else.
|
|
28
|
+
*
|
|
29
|
+
* This is NOT the identity keypair. `so.oxy.identity.OxyIdentityStore` holds the
|
|
30
|
+
* self-custody private key that signs identity approvals and cannot be
|
|
31
|
+
* re-created; this file holds an ordinary session credential the server can
|
|
32
|
+
* revoke and any signed-in app can re-publish. They are separate files behind
|
|
33
|
+
* separate providers with separate permissions precisely so an app that only
|
|
34
|
+
* needs a session is never handed the key.
|
|
35
|
+
*
|
|
36
|
+
* Under `android:sharedUserId="so.oxy.shared"` every Oxy app sees ONE data
|
|
37
|
+
* directory, so this file is literally shared between them — that is the primary
|
|
38
|
+
* transport, and [OxyDeviceSessionProvider] extends the same bytes to a
|
|
39
|
+
* same-signature app outside the UID.
|
|
40
|
+
*/
|
|
41
|
+
internal object OxyDeviceSessionStore {
|
|
42
|
+
/**
|
|
43
|
+
* Global (not package-suffixed) on purpose — the opposite choice from
|
|
44
|
+
* `oxy_background_session`, and for the opposite reason. That store is
|
|
45
|
+
* per-app precisely so one app cannot touch another's widget credential. This
|
|
46
|
+
* one EXISTS to be one value shared by every app in the UID; scoping it per
|
|
47
|
+
* package would give each app its own copy and defeat the whole point.
|
|
48
|
+
*/
|
|
49
|
+
const val PREFS_NAME = "oxy_shared_device_session"
|
|
50
|
+
const val KEY_DEVICE_ID = "deviceId"
|
|
51
|
+
const val KEY_DEVICE_SECRET = "deviceSecret"
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* [RecoveryPolicy.RebuildFileOnly] — this store must NEVER escalate to a
|
|
55
|
+
* UID-shared master-key reset.
|
|
56
|
+
*
|
|
57
|
+
* What it holds is DERIVED: every signed-in app re-publishes the credential
|
|
58
|
+
* from its own durable copy, so losing this file costs at most one interactive
|
|
59
|
+
* sign-in on a device that has no other Oxy app installed. A master-key reset
|
|
60
|
+
* would wipe every other Oxy store sharing the alias — including the
|
|
61
|
+
* self-custody identity keypair, which is IRREPLACEABLE. Trading someone's
|
|
62
|
+
* unrecoverable identity to save a credential we can simply re-publish is never
|
|
63
|
+
* the right trade, so the escalation is not merely discouraged here, it is
|
|
64
|
+
* unreachable.
|
|
65
|
+
*
|
|
66
|
+
* Consequence worth stating: a stage-1 heal WIPES this file. That surfaces as
|
|
67
|
+
* `Absent`, which is honest — after the wipe the slot really is empty, and the
|
|
68
|
+
* next successful mint in any app re-seeds it.
|
|
69
|
+
*/
|
|
70
|
+
private fun prefs(context: Context): SharedPreferences =
|
|
71
|
+
OxyEncryptedPrefs.open(context, PREFS_NAME, RecoveryPolicy.RebuildFileOnly)
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Read the credential. A thrown open (the keyset is unreadable and the policy
|
|
75
|
+
* above refuses to escalate) is reported as [DeviceSessionRead.Unavailable] —
|
|
76
|
+
* never as absent.
|
|
77
|
+
*/
|
|
78
|
+
fun read(context: Context): DeviceSessionRead =
|
|
79
|
+
runCatching {
|
|
80
|
+
val p = prefs(context)
|
|
81
|
+
val deviceId = p.getString(KEY_DEVICE_ID, null)
|
|
82
|
+
val deviceSecret = p.getString(KEY_DEVICE_SECRET, null)
|
|
83
|
+
if (deviceId.isNullOrEmpty() || deviceSecret.isNullOrEmpty()) {
|
|
84
|
+
DeviceSessionRead.Absent
|
|
85
|
+
} else {
|
|
86
|
+
DeviceSessionRead.Present(deviceId, deviceSecret)
|
|
87
|
+
}
|
|
88
|
+
}.getOrElse { DeviceSessionRead.Unavailable(it.javaClass.simpleName) }
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Replace the credential, returning whether a read-back confirmed it landed.
|
|
92
|
+
*
|
|
93
|
+
* The read-back is the contract JS relies on: a fresh install adopts whatever
|
|
94
|
+
* is in this slot, so publishing a value that did not actually persist would
|
|
95
|
+
* send it into a mint that can never succeed.
|
|
96
|
+
*
|
|
97
|
+
* `commit()` (synchronous) so a cross-process reader firing immediately after
|
|
98
|
+
* the write sees the flushed value.
|
|
99
|
+
*/
|
|
100
|
+
fun write(context: Context, deviceId: String, deviceSecret: String): Boolean =
|
|
101
|
+
runCatching {
|
|
102
|
+
val p = prefs(context)
|
|
103
|
+
p.edit()
|
|
104
|
+
.putString(KEY_DEVICE_ID, deviceId)
|
|
105
|
+
.putString(KEY_DEVICE_SECRET, deviceSecret)
|
|
106
|
+
.commit()
|
|
107
|
+
p.getString(KEY_DEVICE_ID, null) == deviceId &&
|
|
108
|
+
p.getString(KEY_DEVICE_SECRET, null) == deviceSecret
|
|
109
|
+
}.getOrDefault(false)
|
|
110
|
+
|
|
111
|
+
/** Drop the shared credential. Best-effort; safe to call when already empty. */
|
|
112
|
+
fun clear(context: Context) {
|
|
113
|
+
runCatching { prefs(context).edit().clear().commit() }
|
|
114
|
+
}
|
|
115
|
+
}
|
package/expo-module.config.json
CHANGED
package/lib/commonjs/index.js
CHANGED
|
@@ -129,6 +129,18 @@ Object.defineProperty(exports, "OxyProvider", {
|
|
|
129
129
|
return _OxyProvider.default;
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
+
Object.defineProperty(exports, "OxyProviderMissingError", {
|
|
133
|
+
enumerable: true,
|
|
134
|
+
get: function () {
|
|
135
|
+
return _OxyContext.OxyProviderMissingError;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
Object.defineProperty(exports, "OxyRuntimeMissingError", {
|
|
139
|
+
enumerable: true,
|
|
140
|
+
get: function () {
|
|
141
|
+
return _index.OxyRuntimeMissingError;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
132
144
|
Object.defineProperty(exports, "OxySignInButton", {
|
|
133
145
|
enumerable: true,
|
|
134
146
|
get: function () {
|
|
@@ -393,10 +405,10 @@ Object.defineProperty(exports, "useAccountStorageUsage", {
|
|
|
393
405
|
return _useServicesQueries.useAccountStorageUsage;
|
|
394
406
|
}
|
|
395
407
|
});
|
|
396
|
-
Object.defineProperty(exports, "
|
|
408
|
+
Object.defineProperty(exports, "useActiveAccount", {
|
|
397
409
|
enumerable: true,
|
|
398
410
|
get: function () {
|
|
399
|
-
return
|
|
411
|
+
return _index.useActiveAccount;
|
|
400
412
|
}
|
|
401
413
|
});
|
|
402
414
|
Object.defineProperty(exports, "useAsset", {
|
|
@@ -483,12 +495,24 @@ Object.defineProperty(exports, "useCurrentUser", {
|
|
|
483
495
|
return _useAccountQueries.useCurrentUser;
|
|
484
496
|
}
|
|
485
497
|
});
|
|
498
|
+
Object.defineProperty(exports, "useDeviceDirectory", {
|
|
499
|
+
enumerable: true,
|
|
500
|
+
get: function () {
|
|
501
|
+
return _index.useDeviceDirectory;
|
|
502
|
+
}
|
|
503
|
+
});
|
|
486
504
|
Object.defineProperty(exports, "useDeviceSessions", {
|
|
487
505
|
enumerable: true,
|
|
488
506
|
get: function () {
|
|
489
507
|
return _useServicesQueries.useDeviceSessions;
|
|
490
508
|
}
|
|
491
509
|
});
|
|
510
|
+
Object.defineProperty(exports, "useDeviceSwitcher", {
|
|
511
|
+
enumerable: true,
|
|
512
|
+
get: function () {
|
|
513
|
+
return _useDeviceSwitcher.useDeviceSwitcher;
|
|
514
|
+
}
|
|
515
|
+
});
|
|
492
516
|
Object.defineProperty(exports, "useFileDownloadUrl", {
|
|
493
517
|
enumerable: true,
|
|
494
518
|
get: function () {
|
|
@@ -561,6 +585,12 @@ Object.defineProperty(exports, "useOnlineStatus", {
|
|
|
561
585
|
return _useOnlineStatus.useOnlineStatus;
|
|
562
586
|
}
|
|
563
587
|
});
|
|
588
|
+
Object.defineProperty(exports, "useOptionalOxy", {
|
|
589
|
+
enumerable: true,
|
|
590
|
+
get: function () {
|
|
591
|
+
return _OxyContext.useOptionalOxy;
|
|
592
|
+
}
|
|
593
|
+
});
|
|
564
594
|
Object.defineProperty(exports, "useOxy", {
|
|
565
595
|
enumerable: true,
|
|
566
596
|
get: function () {
|
|
@@ -573,6 +603,18 @@ Object.defineProperty(exports, "useOxyEvent", {
|
|
|
573
603
|
return _useOxyEvent.useOxyEvent;
|
|
574
604
|
}
|
|
575
605
|
});
|
|
606
|
+
Object.defineProperty(exports, "useOxyRuntime", {
|
|
607
|
+
enumerable: true,
|
|
608
|
+
get: function () {
|
|
609
|
+
return _index.useOxyRuntime;
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
Object.defineProperty(exports, "useOxySnapshot", {
|
|
613
|
+
enumerable: true,
|
|
614
|
+
get: function () {
|
|
615
|
+
return _index.useOxySnapshot;
|
|
616
|
+
}
|
|
617
|
+
});
|
|
576
618
|
Object.defineProperty(exports, "usePrivacySettings", {
|
|
577
619
|
enumerable: true,
|
|
578
620
|
get: function () {
|
|
@@ -645,12 +687,6 @@ Object.defineProperty(exports, "useSwitchSession", {
|
|
|
645
687
|
return _useServicesMutations.useSwitchSession;
|
|
646
688
|
}
|
|
647
689
|
});
|
|
648
|
-
Object.defineProperty(exports, "useSwitchableAccounts", {
|
|
649
|
-
enumerable: true,
|
|
650
|
-
get: function () {
|
|
651
|
-
return _useSwitchableAccounts.useSwitchableAccounts;
|
|
652
|
-
}
|
|
653
|
-
});
|
|
654
690
|
Object.defineProperty(exports, "useUpdateAccountSettings", {
|
|
655
691
|
enumerable: true,
|
|
656
692
|
get: function () {
|
|
@@ -775,10 +811,10 @@ var _core = require("@oxyhq/core");
|
|
|
775
811
|
var _reactNative = require("react-native");
|
|
776
812
|
var _OxyProvider = _interopRequireDefault(require("./ui/components/OxyProvider.js"));
|
|
777
813
|
var _OxyContext = require("./ui/context/OxyContext.js");
|
|
814
|
+
var _index = require("./ui/runtime/index.js");
|
|
778
815
|
var _useAuth = require("./ui/hooks/useAuth.js");
|
|
779
816
|
var _identityBinding = require("./ui/session/identityBinding.js");
|
|
780
817
|
var _authStore = require("./ui/stores/authStore.js");
|
|
781
|
-
var _accountStore = require("./ui/stores/accountStore.js");
|
|
782
818
|
var _assetStore = require("./ui/stores/assetStore.js");
|
|
783
819
|
var _useAssets = require("./ui/hooks/useAssets.js");
|
|
784
820
|
var _useFileDownloadUrl = require("./ui/hooks/useFileDownloadUrl.js");
|
|
@@ -816,7 +852,7 @@ var _LogoText = require("./ui/components/logo/LogoText.js");
|
|
|
816
852
|
var _ProfileButton = _interopRequireDefault(require("./ui/components/ProfileButton.js"));
|
|
817
853
|
var _OxyAuthChooser = _interopRequireDefault(require("./ui/components/OxyAuthChooser.js"));
|
|
818
854
|
var _OxySignInRequestSurface = require("./ui/components/OxySignInRequestSurface.js");
|
|
819
|
-
var
|
|
855
|
+
var _useDeviceSwitcher = require("./ui/hooks/useDeviceSwitcher.js");
|
|
820
856
|
var _ProfileScreen = _interopRequireDefault(require("./ui/screens/ProfileScreen.js"));
|
|
821
857
|
var _ManageAccountScreen = _interopRequireDefault(require("./ui/screens/ManageAccountScreen.js"));
|
|
822
858
|
var _NotificationsScreen = _interopRequireDefault(require("./ui/screens/NotificationsScreen.js"));
|
|
@@ -862,6 +898,14 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
862
898
|
// Provider + auth context
|
|
863
899
|
// ---------------------------------------------------------------------------
|
|
864
900
|
|
|
901
|
+
// `useOxy()` THROWS when no provider is mounted. `useOptionalOxy()` returns
|
|
902
|
+
// `null` instead, for the rare component that renders on both sides of the
|
|
903
|
+
// provider boundary; there is no fabricated forever-loading runtime.
|
|
904
|
+
|
|
905
|
+
// The runtime surface (ADR 0004). These subscribe to the ONE runtime with a
|
|
906
|
+
// selector, so — unlike `useOxy()`, whose value is rebuilt by any of its fifty
|
|
907
|
+
// members moving — a locale change or a dialog opening does not re-render them.
|
|
908
|
+
|
|
865
909
|
// Thrown by `switchToAccount` / `switchSession` while `OxyProvider` runs with
|
|
866
910
|
// `sessionMode="identity"` — an identity-bound app authenticates as the owner of
|
|
867
911
|
// the local identity key and cannot switch accounts.
|
|
@@ -968,12 +1012,12 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
968
1012
|
// no controller: `route` + `progress` + `qrPayload` + the failure flags are the
|
|
969
1013
|
// whole contract, and none of them is a secret credential.
|
|
970
1014
|
|
|
971
|
-
//
|
|
972
|
-
//
|
|
973
|
-
//
|
|
974
|
-
//
|
|
975
|
-
//
|
|
976
|
-
//
|
|
1015
|
+
// The device switcher — the server's own directory (ADR 0002) of who is signed
|
|
1016
|
+
// in here and what each of them may act as, grouped by PERSON, with the two
|
|
1017
|
+
// removals an account id cannot name. Backed by the shared
|
|
1018
|
+
// `AccountDialogController` in `@oxyhq/core`; selecting a row activates a
|
|
1019
|
+
// `contextId`. `DevicePrincipalGroup` and `DeviceContext` live in `@oxyhq/core`
|
|
1020
|
+
// — import them from there.
|
|
977
1021
|
|
|
978
1022
|
// Unified "Manage your Oxy Account" screen (the caller's own personal account)
|
|
979
1023
|
|