@oxyhq/services 23.2.0 → 24.0.1

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.
Files changed (172) hide show
  1. package/android/src/main/java/so/oxy/identity/OxyIdentityStore.kt +21 -127
  2. package/android/src/main/java/so/oxy/session/OxyBackgroundSession.kt +184 -0
  3. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionApi.kt +162 -0
  4. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionModule.kt +101 -0
  5. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionStore.kt +179 -0
  6. package/android/src/main/java/so/oxy/session/OxyBackgroundToken.kt +61 -0
  7. package/android/src/main/java/so/oxy/storage/OxyEncryptedPrefs.kt +241 -0
  8. package/expo-module.config.json +4 -1
  9. package/lib/commonjs/ui/components/OxyProvider.js +3 -1
  10. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  11. package/lib/commonjs/ui/components/ProfileButton.js +1 -1
  12. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  13. package/lib/commonjs/ui/components/internal/PinInput.js +3 -1
  14. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  15. package/lib/commonjs/ui/components/logo/LogoText.js +4 -4
  16. package/lib/commonjs/ui/components/logo/LogoText.js.map +1 -1
  17. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js +2 -2
  18. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  19. package/lib/commonjs/ui/context/OxyContext.js +13 -0
  20. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  21. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +2 -3
  22. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  23. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +2 -3
  24. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -1
  25. package/lib/commonjs/ui/screens/EditProfileScreen.js +2 -3
  26. package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -1
  27. package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -1
  28. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/ManageAccountScreen.js +1 -1
  30. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +2 -2
  32. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +8 -9
  34. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
  36. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/UserListScreen.js +2 -3
  38. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +1 -1
  40. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +2 -3
  42. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +1 -1
  44. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  45. package/lib/commonjs/ui/session/backgroundSession.js +264 -0
  46. package/lib/commonjs/ui/session/backgroundSession.js.map +1 -0
  47. package/lib/commonjs/ui/session/index.js +7 -0
  48. package/lib/commonjs/ui/session/index.js.map +1 -1
  49. package/lib/commonjs/ui/session/useBackgroundSessionSync.js +81 -0
  50. package/lib/commonjs/ui/session/useBackgroundSessionSync.js.map +1 -0
  51. package/lib/commonjs/ui/utils/userUtils.js +31 -22
  52. package/lib/commonjs/ui/utils/userUtils.js.map +1 -1
  53. package/lib/module/ui/components/OxyProvider.js +3 -1
  54. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  55. package/lib/module/ui/components/ProfileButton.js +2 -2
  56. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  57. package/lib/module/ui/components/internal/PinInput.js +3 -1
  58. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  59. package/lib/module/ui/components/logo/LogoText.js +4 -4
  60. package/lib/module/ui/components/logo/LogoText.js.map +1 -1
  61. package/lib/module/ui/components/payment/PaymentSummaryStep.js +2 -2
  62. package/lib/module/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  63. package/lib/module/ui/context/OxyContext.js +14 -1
  64. package/lib/module/ui/context/OxyContext.js.map +1 -1
  65. package/lib/module/ui/screens/AccountSettingsScreen.js +2 -3
  66. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  67. package/lib/module/ui/screens/ChangeAvatarScreen.js +3 -4
  68. package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -1
  69. package/lib/module/ui/screens/EditProfileScreen.js +3 -4
  70. package/lib/module/ui/screens/EditProfileScreen.js.map +1 -1
  71. package/lib/module/ui/screens/FeedbackScreen.js +3 -1
  72. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  73. package/lib/module/ui/screens/ManageAccountScreen.js +2 -2
  74. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  75. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +2 -2
  76. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  77. package/lib/module/ui/screens/PrivacySettingsScreen.js +9 -10
  78. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  79. package/lib/module/ui/screens/ProfileScreen.js +1 -1
  80. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  81. package/lib/module/ui/screens/UserListScreen.js +2 -3
  82. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  83. package/lib/module/ui/screens/trust/TrustCenterScreen.js +1 -1
  84. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  85. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +2 -3
  86. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  87. package/lib/module/ui/screens/trust/TrustRewardsScreen.js +1 -1
  88. package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  89. package/lib/module/ui/session/backgroundSession.js +258 -0
  90. package/lib/module/ui/session/backgroundSession.js.map +1 -0
  91. package/lib/module/ui/session/index.js +1 -0
  92. package/lib/module/ui/session/index.js.map +1 -1
  93. package/lib/module/ui/session/useBackgroundSessionSync.js +76 -0
  94. package/lib/module/ui/session/useBackgroundSessionSync.js.map +1 -0
  95. package/lib/module/ui/utils/userUtils.js +31 -22
  96. package/lib/module/ui/utils/userUtils.js.map +1 -1
  97. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
  99. package/lib/typescript/commonjs/ui/components/internal/PinInput.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  101. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +22 -0
  102. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
  103. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -1
  104. package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -1
  105. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
  106. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
  109. package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts +1 -1
  110. package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/ui/session/backgroundSession.d.ts +42 -0
  112. package/lib/typescript/commonjs/ui/session/backgroundSession.d.ts.map +1 -0
  113. package/lib/typescript/commonjs/ui/session/index.d.ts +1 -0
  114. package/lib/typescript/commonjs/ui/session/index.d.ts.map +1 -1
  115. package/lib/typescript/commonjs/ui/session/useBackgroundSessionSync.d.ts +23 -0
  116. package/lib/typescript/commonjs/ui/session/useBackgroundSessionSync.d.ts.map +1 -0
  117. package/lib/typescript/commonjs/ui/types/navigation.d.ts +7 -0
  118. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/ui/utils/userUtils.d.ts +7 -12
  120. package/lib/typescript/commonjs/ui/utils/userUtils.d.ts.map +1 -1
  121. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  122. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
  123. package/lib/typescript/module/ui/components/internal/PinInput.d.ts.map +1 -1
  124. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  125. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +22 -0
  126. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
  127. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -1
  128. package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -1
  129. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
  130. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  131. package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  132. package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
  133. package/lib/typescript/module/ui/screens/trust/trustTier.d.ts +1 -1
  134. package/lib/typescript/module/ui/screens/trust/trustTier.d.ts.map +1 -1
  135. package/lib/typescript/module/ui/session/backgroundSession.d.ts +42 -0
  136. package/lib/typescript/module/ui/session/backgroundSession.d.ts.map +1 -0
  137. package/lib/typescript/module/ui/session/index.d.ts +1 -0
  138. package/lib/typescript/module/ui/session/index.d.ts.map +1 -1
  139. package/lib/typescript/module/ui/session/useBackgroundSessionSync.d.ts +23 -0
  140. package/lib/typescript/module/ui/session/useBackgroundSessionSync.d.ts.map +1 -0
  141. package/lib/typescript/module/ui/types/navigation.d.ts +7 -0
  142. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  143. package/lib/typescript/module/ui/utils/userUtils.d.ts +7 -12
  144. package/lib/typescript/module/ui/utils/userUtils.d.ts.map +1 -1
  145. package/package.json +5 -5
  146. package/src/ui/components/OxyProvider.tsx +2 -0
  147. package/src/ui/components/ProfileButton.tsx +5 -2
  148. package/src/ui/components/internal/PinInput.tsx +1 -0
  149. package/src/ui/components/logo/LogoText.tsx +4 -4
  150. package/src/ui/components/payment/PaymentSummaryStep.tsx +2 -2
  151. package/src/ui/context/OxyContext.tsx +14 -0
  152. package/src/ui/context/oxyContextTypes.ts +22 -0
  153. package/src/ui/screens/AccountSettingsScreen.tsx +4 -4
  154. package/src/ui/screens/ChangeAvatarScreen.tsx +6 -3
  155. package/src/ui/screens/EditProfileScreen.tsx +6 -3
  156. package/src/ui/screens/FeedbackScreen.tsx +1 -0
  157. package/src/ui/screens/ManageAccountScreen.tsx +8 -1
  158. package/src/ui/screens/PremiumSubscriptionScreen.tsx +2 -2
  159. package/src/ui/screens/PrivacySettingsScreen.tsx +13 -11
  160. package/src/ui/screens/ProfileScreen.tsx +3 -1
  161. package/src/ui/screens/UserListScreen.tsx +2 -2
  162. package/src/ui/screens/trust/TrustCenterScreen.tsx +2 -2
  163. package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +3 -3
  164. package/src/ui/screens/trust/TrustRewardsScreen.tsx +1 -1
  165. package/src/ui/screens/trust/TrustRulesScreen.tsx +1 -1
  166. package/src/ui/screens/trust/trustTier.ts +1 -1
  167. package/src/ui/session/__tests__/backgroundSession.test.ts +387 -0
  168. package/src/ui/session/backgroundSession.ts +299 -0
  169. package/src/ui/session/index.ts +1 -0
  170. package/src/ui/session/useBackgroundSessionSync.ts +92 -0
  171. package/src/ui/types/navigation.ts +7 -0
  172. package/src/ui/utils/userUtils.ts +34 -20
@@ -176,6 +176,28 @@ export interface OxyContextProviderProps {
176
176
  * @default 'popup'
177
177
  */
178
178
  webAuthMode?: WebAuthMode;
179
+ /**
180
+ * Let NATIVE background code (a home-screen widget's WorkManager worker, a sync
181
+ * job) authenticate while the app process is dead and there is no JS runtime.
182
+ *
183
+ * With this on, the SDK provisions a purpose-built background credential
184
+ * whenever the app runs and stores it where `so.oxy.session.OxyBackgroundSession`
185
+ * can read it; Kotlin then exchanges it for a short access token on demand. The
186
+ * app writes no session code — this prop is the whole integration.
187
+ *
188
+ * OFF by default, because a credential that nobody needs is exposure that
189
+ * nobody needs. Turn it on only in an app that actually has background code to
190
+ * authenticate. Android-only today; inert on web and iOS.
191
+ *
192
+ * The credential cannot create a session (only the running app can provision
193
+ * one), cannot rotate or otherwise disturb the app's own device credential, and
194
+ * is re-authorized server-side on every use so it can never outlive a sign-out.
195
+ * It does NOT reduce authority: the token it mints is a full user access token,
196
+ * exactly like the device credential's.
197
+ *
198
+ * @default false
199
+ */
200
+ backgroundSession?: boolean;
179
201
  onAuthStateChange?: (user: User | null) => void;
180
202
  onError?: (error: ApiError) => void;
181
203
  }
@@ -12,7 +12,7 @@ import { Text } from '@oxyhq/bloom/typography';
12
12
  import { Button } from '@oxyhq/bloom/button';
13
13
  import { TextField, TextFieldInput } from '@oxyhq/bloom/text-field';
14
14
  import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
15
- import type { UpdateAccountInput } from '@oxyhq/core';
15
+ import { getNormalizedUserHandle, type UpdateAccountInput } from '@oxyhq/core';
16
16
  import type { BaseScreenProps } from '../types/navigation';
17
17
  import { SettingsIcon } from '../components/SettingsIcon';
18
18
  import { useOxy } from '../context/OxyContext';
@@ -67,9 +67,9 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, nav
67
67
  // Seed the form from the account during render (no useEffect): the first time
68
68
  // the query resolves we capture its values into local edit state.
69
69
  if (node && !seeded) {
70
- const first = node.account?.name?.first ?? '';
71
- const last = node.account?.name?.last ?? '';
72
- setDisplayName([first, last].filter(Boolean).join(' '));
70
+ setDisplayName(
71
+ node.account?.name?.displayName ?? getNormalizedUserHandle(node.account) ?? '',
72
+ );
73
73
  setBio(node.account?.bio ?? '');
74
74
  setSeeded(true);
75
75
  }
@@ -40,7 +40,7 @@ import {
40
40
  import { surfaces as bloomSurfaces } from '@oxyhq/bloom/surfaces';
41
41
  import { useTheme } from '@oxyhq/bloom/theme';
42
42
  import { toast } from '@oxyhq/bloom';
43
- import { getAccountDisplayName, logger } from '@oxyhq/core';
43
+ import { getNormalizedUserHandle, logger } from '@oxyhq/core';
44
44
  import type { FileMetadata } from '@oxyhq/core';
45
45
  import { useOxy } from '../context/OxyContext';
46
46
  import { useI18n } from '../hooks/useI18n';
@@ -133,7 +133,7 @@ async function loadImagePicker(): Promise<ImagePickerModule | null> {
133
133
 
134
134
  const ChangeAvatarScreen: React.FC<BaseScreenProps> = ({ navigate, dismiss }) => {
135
135
  const bloomTheme = useTheme();
136
- const { t, locale } = useI18n();
136
+ const { t } = useI18n();
137
137
  const { user, oxyServices } = useOxy();
138
138
 
139
139
  /** Set when a permission was refused — drives the inline denied notice. */
@@ -143,7 +143,10 @@ const ChangeAvatarScreen: React.FC<BaseScreenProps> = ({ navigate, dismiss }) =>
143
143
 
144
144
  useSurfaceHeader(useMemo(() => ({ title: t('changeAvatar.title') }), [t]));
145
145
 
146
- const displayName = useMemo(() => getAccountDisplayName(user, locale), [user, locale]);
146
+ const displayName = useMemo(
147
+ () => user?.name?.displayName ?? getNormalizedUserHandle(user) ?? '',
148
+ [user],
149
+ );
147
150
  const avatarUri = useMemo(
148
151
  // `thumb` is 256x256 — exactly a 2x source for the 132dp hero.
149
152
  () => (user?.avatar ? oxyServices.getFileDownloadUrl(user.avatar, 'thumb') : undefined),
@@ -3,7 +3,7 @@ import { useMemo } from 'react';
3
3
  import { View } from 'react-native';
4
4
  import { useTheme } from '@oxyhq/bloom/theme';
5
5
  import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
6
- import { getAccountDisplayName } from '@oxyhq/core';
6
+ import { getNormalizedUserHandle } from '@oxyhq/core';
7
7
  import type { BaseScreenProps } from '../types/navigation';
8
8
  import { Avatar } from '@oxyhq/bloom/avatar';
9
9
  import ProfileSummaryCard from '../components/ProfileSummaryCard';
@@ -24,12 +24,15 @@ import type { ProfileFieldType } from './EditProfileFieldScreen';
24
24
  */
25
25
  const EditProfileScreen: React.FC<BaseScreenProps> = ({ navigate }) => {
26
26
  const bloomTheme = useTheme();
27
- const { t, locale } = useI18n();
27
+ const { t } = useI18n();
28
28
  const { user, oxyServices, openAvatarPicker } = useOxy();
29
29
 
30
30
  useSurfaceHeader({ title: t('editProfile.title') || 'Edit Profile' });
31
31
 
32
- const displayName = useMemo(() => getAccountDisplayName(user, locale), [user, locale]);
32
+ const displayName = useMemo(
33
+ () => user?.name?.displayName ?? getNormalizedUserHandle(user) ?? '',
34
+ [user],
35
+ );
33
36
  const avatarUri = useMemo(
34
37
  () => (user?.avatar ? oxyServices.getFileDownloadUrl(user.avatar, 'thumb') : undefined),
35
38
  [user?.avatar, oxyServices],
@@ -283,6 +283,7 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
283
283
  >
284
284
  {Array.from({ length: TOTAL_STEPS }, (_, index) => (
285
285
  <View
286
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixed step indicators, order never changes
286
287
  key={index}
287
288
  className={
288
289
  currentStep === index
@@ -15,6 +15,7 @@ import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list'
15
15
  import {
16
16
  getAccountDisplayName,
17
17
  getAccountFallbackHandle,
18
+ getNormalizedUserHandle,
18
19
  logger as loggerUtil,
19
20
  packageInfo,
20
21
  } from '@oxyhq/core';
@@ -120,7 +121,13 @@ const ManageAccountScreen: React.FC<BaseScreenProps> = ({
120
121
  const [signingOutAllDevices, setSigningOutAllDevices] = useState(false);
121
122
  const [signingOut, setSigningOut] = useState(false);
122
123
 
123
- const displayName = useMemo(() => getAccountDisplayName(user, locale), [user, locale]);
124
+ const displayName = useMemo(
125
+ () =>
126
+ user?.name?.displayName ??
127
+ getNormalizedUserHandle(user) ??
128
+ getAccountDisplayName(null, locale),
129
+ [user, locale],
130
+ );
124
131
  const handle = useMemo(() => getAccountFallbackHandle(user), [user]);
125
132
  const avatarUri = useMemo(() => {
126
133
  return user?.avatar
@@ -741,9 +741,9 @@ const PremiumSubscriptionScreen: React.FC<BaseScreenProps> = ({
741
741
  </View>
742
742
 
743
743
  <BenefitList className="mb-space-24">
744
- {plan.features.map((feature, index) => (
744
+ {plan.features.map((feature) => (
745
745
  <BenefitRow
746
- key={index}
746
+ key={feature}
747
747
  icon={<Ionicons name="checkmark" size={18} color={colors.success} />}
748
748
  label={feature}
749
749
  />
@@ -14,7 +14,7 @@ import { useI18n } from '../hooks/useI18n';
14
14
  import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
15
15
  import { useSettingToggles } from '../hooks/useSettingToggle';
16
16
  import type { BlockedUser, RestrictedUser } from '@oxyhq/core';
17
- import { getAccountDisplayName } from '@oxyhq/core';
17
+ import { getNormalizedUserHandle } from '@oxyhq/core';
18
18
  import { useOxy } from '../context/OxyContext';
19
19
 
20
20
  interface PrivacySettings {
@@ -68,7 +68,7 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
68
68
  // Privacy settings belong to the ACTIVE account (the org/project/bot when
69
69
  // switched, else the personal user).
70
70
  const { oxyServices, user } = useOxy();
71
- const { t, locale } = useI18n();
71
+ const { t } = useI18n();
72
72
 
73
73
  useSurfaceHeader({ title: t('privacySettings.title') || 'Privacy Settings' });
74
74
  const bloomTheme = useTheme();
@@ -176,35 +176,37 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
176
176
  }, [oxyServices, t]);
177
177
 
178
178
  // Helper to extract user info from blocked/restricted objects.
179
- // Display names go through the canonical helper so the fallback chain is
180
- // identical across every UI surface (name → username → publicKey → "Unnamed").
181
179
  const extractUserInfo = useCallback((
182
180
  item: BlockedUser | RestrictedUser,
183
181
  idField: 'blockedId' | 'restrictedId'
184
182
  ) => {
185
- let userIdField: string | { _id: string; username?: string; avatar?: string };
186
- let userShape: { username?: string };
183
+ let userIdField: string | { _id: string; username?: string; avatar?: string; name?: { displayName?: string } };
184
+ let userShape: { username?: string; name?: { displayName?: string } };
187
185
  let avatar: string | undefined;
188
186
 
189
187
  if (idField === 'blockedId' && 'blockedId' in item) {
190
188
  userIdField = item.blockedId;
191
189
  userShape = typeof item.blockedId === 'string'
192
190
  ? { username: item.username }
193
- : { username: item.blockedId.username };
191
+ : { username: item.blockedId.username, name: item.blockedId.name };
194
192
  avatar = typeof item.blockedId === 'string' ? item.avatar : item.blockedId.avatar;
195
193
  } else if (idField === 'restrictedId' && 'restrictedId' in item) {
196
194
  userIdField = item.restrictedId;
197
195
  userShape = typeof item.restrictedId === 'string'
198
196
  ? { username: item.username }
199
- : { username: item.restrictedId.username };
197
+ : { username: item.restrictedId.username, name: item.restrictedId.name };
200
198
  avatar = typeof item.restrictedId === 'string' ? item.avatar : item.restrictedId.avatar;
201
199
  } else {
202
- return { userId: '', displayName: getAccountDisplayName(null, locale), avatar: undefined };
200
+ return { userId: '', displayName: getNormalizedUserHandle(null) ?? '', avatar: undefined };
203
201
  }
204
202
 
205
203
  const userId = typeof userIdField === 'string' ? userIdField : userIdField._id;
206
- return { userId, displayName: getAccountDisplayName(userShape, locale), avatar };
207
- }, [locale]);
204
+ return {
205
+ userId,
206
+ displayName: userShape.name?.displayName ?? getNormalizedUserHandle(userShape) ?? '',
207
+ avatar,
208
+ };
209
+ }, []);
208
210
 
209
211
  if (isLoading) {
210
212
  return (
@@ -78,7 +78,9 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
78
78
  );
79
79
  throw err;
80
80
  }),
81
- oxyServices.getReputationBalance(userId)
81
+ (isOwnProfile
82
+ ? oxyServices.getMyReputationBalance()
83
+ : oxyServices.getReputationBalance(userId))
82
84
  .then((balance): { total: number | undefined } => ({ total: balance.total }))
83
85
  .catch((): { total: number | undefined } => ({ total: undefined })),
84
86
  oxyServices.getUserStats
@@ -65,7 +65,7 @@ const UserListScreen: React.FC<UserListScreenProps> = ({
65
65
  const [hasMore, setHasMore] = useState(true);
66
66
 
67
67
  const bloomTheme = useTheme();
68
- const { t, locale } = useI18n();
68
+ const { t } = useI18n();
69
69
 
70
70
  const currentUserId = currentUser ? resolveUserId(currentUser) : '';
71
71
 
@@ -199,7 +199,7 @@ const UserListScreen: React.FC<UserListScreenProps> = ({
199
199
  </TouchableOpacity>
200
200
  );
201
201
  },
202
- [handleUserPress, currentUserId, oxyServices, locale]
202
+ [handleUserPress, currentUserId, oxyServices]
203
203
  );
204
204
 
205
205
  const renderEmpty = useCallback(() => {
@@ -1,7 +1,7 @@
1
1
  import type React from 'react';
2
2
  import { useEffect, useMemo, useState } from 'react';
3
3
  import { View, StyleSheet } from 'react-native';
4
- import type { ReputationTransaction, TrustTier } from '@oxyhq/core';
4
+ import type { ReputationTransaction, TrustTier } from '@oxyhq/contracts';
5
5
  import Ionicons from '@expo/vector-icons/Ionicons';
6
6
  import { Chip } from '@oxyhq/bloom/chip';
7
7
  import { useTheme } from '@oxyhq/bloom/theme';
@@ -36,7 +36,7 @@ const TrustCenterScreen: React.FC<BaseScreenProps> = ({
36
36
  setIsLoading(true);
37
37
  setError(null);
38
38
  Promise.all([
39
- oxyServices.getReputationBalance(user.id),
39
+ oxyServices.getMyReputationBalance(),
40
40
  oxyServices.getReputationTransactions(user.id, 20, 0),
41
41
  ])
42
42
  .then(([balance, txns]) => {
@@ -7,7 +7,7 @@ import {
7
7
  FlatList,
8
8
  TouchableOpacity,
9
9
  } from 'react-native';
10
- import type { ReputationLeaderboardEntry } from '@oxyhq/core';
10
+ import type { ReputationLeaderboardEntry } from '@oxyhq/contracts';
11
11
  import { getNormalizedUserHandle, logger } from '@oxyhq/core';
12
12
  import { useTheme } from '@oxyhq/bloom/theme';
13
13
  import { H6, Text } from '@oxyhq/bloom/typography';
@@ -29,7 +29,7 @@ const PODIUM_RANK = 3;
29
29
 
30
30
  const TrustLeaderboardScreen: React.FC<BaseScreenProps> = ({ navigate }) => {
31
31
  const { oxyServices, user: currentUser } = useOxy();
32
- const { t, locale } = useI18n();
32
+ const { t } = useI18n();
33
33
  const bloomTheme = useTheme();
34
34
 
35
35
  const [leaderboard, setLeaderboard] = useState<ReputationLeaderboardEntry[]>([]);
@@ -116,7 +116,7 @@ const TrustLeaderboardScreen: React.FC<BaseScreenProps> = ({ navigate }) => {
116
116
  </TouchableOpacity>
117
117
  );
118
118
  },
119
- [oxyServices, locale, currentUserId, handleEntryPress, t],
119
+ [oxyServices, currentUserId, handleEntryPress, t],
120
120
  );
121
121
 
122
122
  const keyExtractor = useCallback(
@@ -97,7 +97,7 @@ const TrustRewardsScreen: React.FC<BaseScreenProps> = () => {
97
97
  return;
98
98
  }
99
99
  setIsLoading(true);
100
- oxyServices.getReputationBalance(user.id)
100
+ oxyServices.getMyReputationBalance()
101
101
  .then((balance) => {
102
102
  setReputationTotal(balance.total || 0);
103
103
  })
@@ -4,7 +4,7 @@ import { View, Text } from 'react-native';
4
4
  import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
5
5
  import { Chip } from '@oxyhq/bloom/chip';
6
6
  import { useTheme } from '@oxyhq/bloom/theme';
7
- import type { ReputationRule, ReputationCategory } from '@oxyhq/core';
7
+ import type { ReputationRule, ReputationCategory } from '@oxyhq/contracts';
8
8
  import type { BaseScreenProps } from '../../types/navigation';
9
9
  import { useSurfaceHeader } from '../../hooks/useSurfaceHeader';
10
10
  import { Loading } from '@oxyhq/bloom/loading';
@@ -1,4 +1,4 @@
1
- import type { TrustTier } from '@oxyhq/core';
1
+ import type { TrustTier } from '@oxyhq/contracts';
2
2
 
3
3
  type Translate = (key: string, vars?: Record<string, string | number>) => string;
4
4