@oxy.so/services 9.2.0 → 11.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.
Files changed (234) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/AndroidManifest.xml +6 -6
  3. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionModule.kt +106 -41
  4. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionProvider.kt +45 -32
  5. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionStore.kt +22 -27
  6. package/android/src/main/java/so/oxy/identity/OxyIdentityModule.kt +89 -43
  7. package/android/src/main/java/so/oxy/security/OxyCallerPolicy.kt +97 -0
  8. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionStore.kt +4 -10
  9. package/android/src/main/java/so/oxy/storage/OxyEncryptedPrefs.kt +17 -18
  10. package/ios/OxyIdentityModule.swift +13 -14
  11. package/lib/commonjs/ui/boot/runProviderColdBoot.js +2 -2
  12. package/lib/commonjs/ui/components/BenefitList.js +1 -1
  13. package/lib/commonjs/ui/components/BenefitList.js.map +1 -1
  14. package/lib/commonjs/ui/components/FollowButton.js +2 -2
  15. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  16. package/lib/commonjs/ui/components/FollowTargetButton.js +2 -2
  17. package/lib/commonjs/ui/components/FollowTargetButton.js.map +1 -1
  18. package/lib/commonjs/ui/components/PeableButton.js +1 -2
  19. package/lib/commonjs/ui/components/PeableButton.js.map +1 -1
  20. package/lib/commonjs/ui/components/SurfaceHeaderAction.js +1 -1
  21. package/lib/commonjs/ui/components/SurfaceHeaderAction.js.map +1 -1
  22. package/lib/commonjs/ui/components/SurfaceScreen.js +1 -1
  23. package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
  24. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +1 -1
  25. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  26. package/lib/commonjs/ui/components/authChooser/primitives.js +1 -1
  27. package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
  28. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js +1 -1
  29. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js.map +1 -1
  30. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +2 -2
  31. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  32. package/lib/commonjs/ui/components/payment/PaymentMethodStep.js +2 -2
  33. package/lib/commonjs/ui/components/payment/PaymentMethodStep.js.map +1 -1
  34. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js +2 -2
  35. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js.map +1 -1
  36. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js +1 -1
  37. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  38. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js +2 -2
  39. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  40. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js +1 -1
  41. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js.map +1 -1
  42. package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js +1 -1
  43. package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
  44. package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js +2 -2
  45. package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
  46. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js +2 -1
  47. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js.map +1 -1
  48. package/lib/commonjs/ui/screens/AccountMembersScreen.js +4 -4
  49. package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
  50. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +1 -1
  51. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  52. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +1 -1
  53. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
  54. package/lib/commonjs/ui/screens/DomainsScreen.js +1 -1
  55. package/lib/commonjs/ui/screens/DomainsScreen.js.map +1 -1
  56. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +4 -2
  57. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  58. package/lib/commonjs/ui/screens/FileManagementScreen.js +5 -5
  59. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  60. package/lib/commonjs/ui/screens/HistoryViewScreen.js +1 -1
  61. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  62. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +1 -1
  63. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  64. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +1 -1
  65. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  66. package/lib/commonjs/ui/screens/NotificationsScreen.js +8 -8
  67. package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
  68. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +1 -1
  69. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  70. package/lib/commonjs/ui/screens/PreferencesScreen.js +2 -2
  71. package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
  72. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +37 -37
  73. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  74. package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
  75. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  76. package/lib/commonjs/ui/screens/SearchSettingsScreen.js +5 -5
  77. package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
  78. package/lib/commonjs/ui/screens/UserListScreen.js +1 -1
  79. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  80. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +11 -11
  81. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  82. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js +1 -1
  83. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js.map +1 -1
  84. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +1 -1
  85. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  86. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +1 -1
  87. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  88. package/lib/commonjs/ui/session/tokenLossRecovery.js +1 -1
  89. package/lib/module/ui/boot/runProviderColdBoot.js +2 -2
  90. package/lib/module/ui/components/BenefitList.js +1 -1
  91. package/lib/module/ui/components/BenefitList.js.map +1 -1
  92. package/lib/module/ui/components/FollowButton.js +2 -2
  93. package/lib/module/ui/components/FollowButton.js.map +1 -1
  94. package/lib/module/ui/components/FollowTargetButton.js +2 -2
  95. package/lib/module/ui/components/FollowTargetButton.js.map +1 -1
  96. package/lib/module/ui/components/PeableButton.js +2 -3
  97. package/lib/module/ui/components/PeableButton.js.map +1 -1
  98. package/lib/module/ui/components/SurfaceHeaderAction.js +1 -1
  99. package/lib/module/ui/components/SurfaceHeaderAction.js.map +1 -1
  100. package/lib/module/ui/components/SurfaceScreen.js +1 -1
  101. package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
  102. package/lib/module/ui/components/authChooser/AccountsMenuView.js +1 -1
  103. package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  104. package/lib/module/ui/components/authChooser/primitives.js +1 -1
  105. package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
  106. package/lib/module/ui/components/authChooser/requestSurfaces.js +1 -1
  107. package/lib/module/ui/components/authChooser/requestSurfaces.js.map +1 -1
  108. package/lib/module/ui/components/payment/PaymentDetailsStep.js +2 -2
  109. package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  110. package/lib/module/ui/components/payment/PaymentMethodStep.js +2 -2
  111. package/lib/module/ui/components/payment/PaymentMethodStep.js.map +1 -1
  112. package/lib/module/ui/components/payment/PaymentReviewStep.js +2 -2
  113. package/lib/module/ui/components/payment/PaymentReviewStep.js.map +1 -1
  114. package/lib/module/ui/components/payment/PaymentSuccessStep.js +1 -1
  115. package/lib/module/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  116. package/lib/module/ui/components/payment/PaymentSummaryStep.js +2 -2
  117. package/lib/module/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  118. package/lib/module/ui/components/signIn/OxyAuthScreen.js +1 -1
  119. package/lib/module/ui/components/signIn/OxyAuthScreen.js.map +1 -1
  120. package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js +1 -1
  121. package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
  122. package/lib/module/ui/components/signIn/OxyPasswordPanel.js +2 -2
  123. package/lib/module/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
  124. package/lib/module/ui/components/surfaces/ActionSheetSurface.js +2 -1
  125. package/lib/module/ui/components/surfaces/ActionSheetSurface.js.map +1 -1
  126. package/lib/module/ui/screens/AccountMembersScreen.js +4 -4
  127. package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
  128. package/lib/module/ui/screens/AccountVerificationScreen.js +1 -1
  129. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  130. package/lib/module/ui/screens/ConnectedAppsScreen.js +1 -1
  131. package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
  132. package/lib/module/ui/screens/DomainsScreen.js +1 -1
  133. package/lib/module/ui/screens/DomainsScreen.js.map +1 -1
  134. package/lib/module/ui/screens/EditProfileFieldScreen.js +4 -2
  135. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  136. package/lib/module/ui/screens/FileManagementScreen.js +5 -5
  137. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  138. package/lib/module/ui/screens/HistoryViewScreen.js +1 -1
  139. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  140. package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -1
  141. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  142. package/lib/module/ui/screens/LegalDocumentsScreen.js +1 -1
  143. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  144. package/lib/module/ui/screens/NotificationsScreen.js +8 -8
  145. package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
  146. package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
  147. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  148. package/lib/module/ui/screens/PreferencesScreen.js +2 -2
  149. package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
  150. package/lib/module/ui/screens/PrivacySettingsScreen.js +37 -37
  151. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  152. package/lib/module/ui/screens/ProfileScreen.js +1 -1
  153. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  154. package/lib/module/ui/screens/SearchSettingsScreen.js +5 -5
  155. package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
  156. package/lib/module/ui/screens/UserListScreen.js +1 -1
  157. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  158. package/lib/module/ui/screens/WelcomeNewUserScreen.js +11 -11
  159. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  160. package/lib/module/ui/screens/fileManagement/UploadBar.js +1 -1
  161. package/lib/module/ui/screens/fileManagement/UploadBar.js.map +1 -1
  162. package/lib/module/ui/screens/trust/TrustCenterScreen.js +1 -1
  163. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  164. package/lib/module/ui/screens/trust/TrustRulesScreen.js +1 -1
  165. package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  166. package/lib/module/ui/session/tokenLossRecovery.js +1 -1
  167. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts +2 -2
  168. package/lib/typescript/commonjs/ui/components/BenefitList.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +1 -1
  170. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
  171. package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts +1 -1
  172. package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/ui/components/PeableButton.d.ts.map +1 -1
  174. package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  176. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts +2 -2
  177. package/lib/typescript/module/ui/components/BenefitList.d.ts.map +1 -1
  178. package/lib/typescript/module/ui/components/FollowButton.d.ts +1 -1
  179. package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
  180. package/lib/typescript/module/ui/components/FollowTargetButton.d.ts +1 -1
  181. package/lib/typescript/module/ui/components/FollowTargetButton.d.ts.map +1 -1
  182. package/lib/typescript/module/ui/components/PeableButton.d.ts.map +1 -1
  183. package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -1
  184. package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  185. package/package.json +7 -7
  186. package/plugins/withOxySharedPermissions.js +89 -0
  187. package/plugins/withSharedDeviceSessionProvider.js +26 -71
  188. package/src/ui/boot/runProviderColdBoot.ts +2 -2
  189. package/src/ui/components/BenefitList.tsx +1 -2
  190. package/src/ui/components/FollowButton.tsx +3 -3
  191. package/src/ui/components/FollowTargetButton.tsx +3 -3
  192. package/src/ui/components/PeableButton.tsx +3 -4
  193. package/src/ui/components/SurfaceHeaderAction.tsx +1 -1
  194. package/src/ui/components/SurfaceScreen.tsx +1 -1
  195. package/src/ui/components/__tests__/followButtonAccessibility.test.tsx +9 -0
  196. package/src/ui/components/authChooser/AccountsMenuView.tsx +1 -1
  197. package/src/ui/components/authChooser/primitives.tsx +1 -1
  198. package/src/ui/components/authChooser/requestSurfaces.tsx +1 -1
  199. package/src/ui/components/payment/PaymentDetailsStep.tsx +2 -2
  200. package/src/ui/components/payment/PaymentMethodStep.tsx +2 -2
  201. package/src/ui/components/payment/PaymentReviewStep.tsx +2 -2
  202. package/src/ui/components/payment/PaymentSuccessStep.tsx +1 -1
  203. package/src/ui/components/payment/PaymentSummaryStep.tsx +2 -2
  204. package/src/ui/components/signIn/OxyAuthScreen.tsx +1 -1
  205. package/src/ui/components/signIn/OxyLinkCommonsPanel.tsx +1 -1
  206. package/src/ui/components/signIn/OxyPasswordPanel.tsx +1 -1
  207. package/src/ui/components/surfaces/ActionSheetSurface.tsx +2 -1
  208. package/src/ui/screens/AccountMembersScreen.tsx +4 -4
  209. package/src/ui/screens/AccountVerificationScreen.tsx +1 -1
  210. package/src/ui/screens/ConnectedAppsScreen.tsx +1 -1
  211. package/src/ui/screens/DomainsScreen.tsx +1 -1
  212. package/src/ui/screens/EditProfileFieldScreen.tsx +1 -2
  213. package/src/ui/screens/FileManagementScreen.tsx +5 -5
  214. package/src/ui/screens/HistoryViewScreen.tsx +1 -1
  215. package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
  216. package/src/ui/screens/LegalDocumentsScreen.tsx +1 -1
  217. package/src/ui/screens/NotificationsScreen.tsx +8 -8
  218. package/src/ui/screens/PaymentGatewayScreen.tsx +1 -1
  219. package/src/ui/screens/PreferencesScreen.tsx +2 -2
  220. package/src/ui/screens/PrivacySettingsScreen.tsx +21 -21
  221. package/src/ui/screens/ProfileScreen.tsx +1 -1
  222. package/src/ui/screens/SearchSettingsScreen.tsx +5 -5
  223. package/src/ui/screens/UserListScreen.tsx +1 -1
  224. package/src/ui/screens/WelcomeNewUserScreen.tsx +11 -11
  225. package/src/ui/screens/fileManagement/UploadBar.tsx +1 -1
  226. package/src/ui/screens/trust/TrustCenterScreen.tsx +1 -1
  227. package/src/ui/screens/trust/TrustRulesScreen.tsx +1 -1
  228. package/src/ui/session/__tests__/tokenLossRecovery.test.ts +2 -2
  229. package/src/ui/session/tokenLossRecovery.ts +1 -1
  230. package/android/src/main/java/so/oxy/identity/OxyIdentityProvider.kt +0 -77
  231. package/android/src/main/java/so/oxy/identity/OxyIdentityStore.kt +0 -66
  232. package/plugins/withSharedDeviceSessionReader.js +0 -57
  233. package/plugins/withSharedIdentityProvider.js +0 -83
  234. package/plugins/withSharedIdentityReader.js +0 -46
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Config plugin: withOxySharedPermissions (EVERY Oxy Android app).
3
+ *
4
+ * Oxy Android apps do not share a UID. They share the Oxy identity and the
5
+ * device session with Commons (and Accounts) through signature-protected
6
+ * ContentProvider `call()` IPC, the way apps use `AccountManager`. Crossing a UID
7
+ * needs two `signature`-level permissions:
8
+ *
9
+ * - `so.oxy.permission.IDENTITY` — Commons' identity host
10
+ * (`so.oxy.commons[.dev].identity`): public key, challenge proofs, scoped
11
+ * derivations. Never the private key.
12
+ * - `so.oxy.permission.DEVICE_SESSION` — the device-session hosts
13
+ * (`so.oxy.commons[.dev].devicesession`, `so.oxy.accounts[.dev].devicesession`).
14
+ *
15
+ * This plugin makes the app both DECLARE and REQUEST both, and adds `<queries>`
16
+ * for every host authority:
17
+ *
18
+ * - Declared by every app, not only by the hosts: a signature permission is
19
+ * granted when the requesting app is installed, if the declaring app is
20
+ * already there. With every app declaring it, install order never matters.
21
+ * Android accepts the same declaration from several packages signed with one
22
+ * certificate, and rejects it from a differently-signed one
23
+ * (`INSTALL_FAILED_DUPLICATE_PERMISSION`), which is the protection we want.
24
+ * Every declaration must be identical, which is why this ONE plugin owns
25
+ * them; the provider plugins do not declare anything.
26
+ * - `<queries>`: Android 11+ package visibility hides a provider the app has
27
+ * not declared an interest in, and `ContentResolver.call` then silently finds
28
+ * nothing.
29
+ *
30
+ * `signature` is the whole trust boundary at the manifest level; each provider
31
+ * also checks the calling package and its certificate itself.
32
+ */
33
+ const { withAndroidManifest } = require('@expo/config-plugins');
34
+
35
+ const IDENTITY_PERMISSION = 'so.oxy.permission.IDENTITY';
36
+ const DEVICE_SESSION_PERMISSION = 'so.oxy.permission.DEVICE_SESSION';
37
+ const PERMISSIONS = [IDENTITY_PERMISSION, DEVICE_SESSION_PERMISSION];
38
+
39
+ /**
40
+ * Every host authority an Oxy app calls. Keep in step with `COMMONS_AUTHORITIES`
41
+ * in `OxyIdentityModule.kt` and `HOST_AUTHORITIES` in `OxyDeviceSessionModule.kt`
42
+ * (a test compares them).
43
+ */
44
+ const HOST_AUTHORITIES = [
45
+ 'so.oxy.commons.identity',
46
+ 'so.oxy.commons.dev.identity',
47
+ 'so.oxy.commons.devicesession',
48
+ 'so.oxy.commons.dev.devicesession',
49
+ 'so.oxy.accounts.devicesession',
50
+ 'so.oxy.accounts.dev.devicesession',
51
+ ];
52
+
53
+ function withOxySharedPermissions(config) {
54
+ return withAndroidManifest(config, (modConfig) => {
55
+ const manifest = modConfig.modResults.manifest;
56
+
57
+ manifest.permission = manifest.permission ?? [];
58
+ manifest['uses-permission'] = manifest['uses-permission'] ?? [];
59
+ for (const name of PERMISSIONS) {
60
+ if (!manifest.permission.some((p) => p.$['android:name'] === name)) {
61
+ manifest.permission.push({
62
+ $: { 'android:name': name, 'android:protectionLevel': 'signature' },
63
+ });
64
+ }
65
+ if (!manifest['uses-permission'].some((p) => p.$['android:name'] === name)) {
66
+ manifest['uses-permission'].push({ $: { 'android:name': name } });
67
+ }
68
+ }
69
+
70
+ manifest.queries = manifest.queries ?? [];
71
+ if (manifest.queries.length === 0) {
72
+ manifest.queries.push({});
73
+ }
74
+ const queries = manifest.queries[0];
75
+ queries.provider = queries.provider ?? [];
76
+ for (const authority of HOST_AUTHORITIES) {
77
+ if (!queries.provider.some((p) => p.$['android:authorities'] === authority)) {
78
+ queries.provider.push({ $: { 'android:authorities': authority } });
79
+ }
80
+ }
81
+
82
+ return modConfig;
83
+ });
84
+ }
85
+
86
+ module.exports = withOxySharedPermissions;
87
+ module.exports.IDENTITY_PERMISSION = IDENTITY_PERMISSION;
88
+ module.exports.DEVICE_SESSION_PERMISSION = DEVICE_SESSION_PERMISSION;
89
+ module.exports.HOST_AUTHORITIES = HOST_AUTHORITIES;
@@ -1,86 +1,39 @@
1
1
  /**
2
- * Config plugin: withSharedDeviceSessionProvider (UID-member hub apps).
2
+ * Config plugin: withSharedDeviceSessionProvider (the device-session HOSTS:
3
+ * Commons and Accounts, prod and dev).
3
4
  *
4
- * The shared DeviceSession credential is how several official Oxy apps end up on
5
+ * The shared DeviceSession credential is how the official Oxy apps end up on
5
6
  * ONE `DeviceSession` — and therefore one globally active account context —
6
- * WITHOUT any of them reading Commons's private identity key. This plugin wires
7
- * the Android side of `@oxy.so/services`:
7
+ * without any of them touching the identity key. Oxy apps do not share a UID,
8
+ * so the credential lives in the hosts' own storage, and this plugin declares
9
+ * the provider every other app reads and writes it through:
10
+ * `OxyDeviceSessionProvider` at `${applicationId}.devicesession` (AGP
11
+ * substitutes `${applicationId}` at build), guarded by the `signature`-level
12
+ * `so.oxy.permission.DEVICE_SESSION`.
8
13
  *
9
- * - Defines a `signature`-level permission
10
- * `so.oxy.shared.permission.READ_DEVICE_SESSION`. `signature` means only apps
11
- * signed with the SAME certificate (the shared Oxy release keystore) can hold
12
- * it — the trust boundary is the signing key, not the deprecated `sharedUserId`.
13
- * - Requests that same permission so this app can also read cross-authority.
14
- * - Declares `OxyDeviceSessionProvider` at authority
15
- * `${applicationId}.devicesession` (AGP substitutes `${applicationId}` at
16
- * build), guarded by that permission. The provider is READ-only across the
17
- * process boundary: a sibling may join the device session, never overwrite it.
18
- * - Adds `<queries>` entries so Android 11+ package-visibility filtering never
19
- * hides the sibling providers from the resolver.
14
+ * It declares NO permission itself: every Oxy app, host or not, declares and
15
+ * requests both Oxy permissions through `withOxySharedPermissions`, so the
16
+ * declarations stay identical. Apply that plugin too.
20
17
  *
21
- * WHICH APPS USE THIS PLUGIN: exactly the apps listed in `PROVIDER_AUTHORITIES`
22
- * below, which must be apps inside the `so.oxy.shared` UID. UID members share one
23
- * data directory, so they all serve the SAME file and the sweep in
24
- * `OxyDeviceSessionModule` is deterministic whichever one answers. An app that is
25
- * same-signature but outside that UID must use `withSharedDeviceSessionReader`
26
- * instead — hosting from there would publish a second, independent copy of "the
27
- * shared credential" and make the winner depend on list order.
28
- *
29
- * Keep this list identical to `PROVIDER_AUTHORITIES` in
30
- * `android/src/main/java/so/oxy/devicesession/OxyDeviceSessionModule.kt`.
31
- *
32
- * This is deliberately a SEPARATE permission and a SEPARATE provider from
33
- * `withSharedIdentityProvider`. Two secrets with different blast radii: the
34
- * identity key is self-custody and irreplaceable, the device credential is
35
- * server-revocable and re-publishable. An app that only needs a session gets only
36
- * the second one.
18
+ * WHICH APPS USE THIS PLUGIN: exactly the apps whose authorities are listed in
19
+ * `HOST_AUTHORITIES` of `OxyDeviceSessionModule.kt` (a test compares them).
37
20
  */
38
21
  const { withAndroidManifest } = require('@expo/config-plugins');
39
22
 
40
- const READ_DEVICE_SESSION_PERMISSION = 'so.oxy.shared.permission.READ_DEVICE_SESSION';
23
+ const DEVICE_SESSION_PERMISSION = 'so.oxy.permission.DEVICE_SESSION';
41
24
  const PROVIDER_CLASS = 'so.oxy.devicesession.OxyDeviceSessionProvider';
42
- const PROVIDER_AUTHORITIES = [
43
- 'so.oxy.accounts.devicesession',
44
- 'so.oxy.accounts.dev.devicesession',
25
+
26
+ /** The authorities this plugin can end up hosting, one per host app. */
27
+ const HOST_AUTHORITIES = [
45
28
  'so.oxy.commons.devicesession',
46
29
  'so.oxy.commons.dev.devicesession',
30
+ 'so.oxy.accounts.devicesession',
31
+ 'so.oxy.accounts.dev.devicesession',
47
32
  ];
48
33
 
49
- module.exports = function withSharedDeviceSessionProvider(config) {
34
+ function withSharedDeviceSessionProvider(config) {
50
35
  return withAndroidManifest(config, (modConfig) => {
51
36
  const manifest = modConfig.modResults.manifest;
52
-
53
- // 1. Define the signature-level permission.
54
- manifest['permission'] = manifest['permission'] ?? [];
55
- if (!manifest['permission'].some((p) => p.$['android:name'] === READ_DEVICE_SESSION_PERMISSION)) {
56
- manifest['permission'].push({
57
- $: {
58
- 'android:name': READ_DEVICE_SESSION_PERMISSION,
59
- 'android:protectionLevel': 'signature',
60
- },
61
- });
62
- }
63
-
64
- // 2. Request it (a hub app reads its siblings too — prod ⇆ dev variant).
65
- manifest['uses-permission'] = manifest['uses-permission'] ?? [];
66
- if (!manifest['uses-permission'].some((p) => p.$['android:name'] === READ_DEVICE_SESSION_PERMISSION)) {
67
- manifest['uses-permission'].push({ $: { 'android:name': READ_DEVICE_SESSION_PERMISSION } });
68
- }
69
-
70
- // 3. Make the sibling provider authorities visible under package filtering.
71
- manifest['queries'] = manifest['queries'] ?? [];
72
- if (manifest['queries'].length === 0) {
73
- manifest['queries'].push({});
74
- }
75
- const queries = manifest['queries'][0];
76
- queries.provider = queries.provider ?? [];
77
- for (const authority of PROVIDER_AUTHORITIES) {
78
- if (!queries.provider.some((p) => p.$['android:authorities'] === authority)) {
79
- queries.provider.push({ $: { 'android:authorities': authority } });
80
- }
81
- }
82
-
83
- // 4. Host the provider.
84
37
  const app = manifest.application?.[0];
85
38
  if (!app) {
86
39
  throw new Error('withSharedDeviceSessionProvider: AndroidManifest has no <application>');
@@ -92,11 +45,13 @@ module.exports = function withSharedDeviceSessionProvider(config) {
92
45
  'android:name': PROVIDER_CLASS,
93
46
  'android:authorities': '${applicationId}.devicesession',
94
47
  'android:exported': 'true',
95
- 'android:permission': READ_DEVICE_SESSION_PERMISSION,
48
+ 'android:permission': DEVICE_SESSION_PERMISSION,
96
49
  },
97
50
  });
98
51
  }
99
-
100
52
  return modConfig;
101
53
  });
102
- };
54
+ }
55
+
56
+ module.exports = withSharedDeviceSessionProvider;
57
+ module.exports.HOST_AUTHORITIES = HOST_AUTHORITIES;
@@ -91,8 +91,8 @@ export interface RunProviderColdBootOptions {
91
91
  *
92
92
  * Ordered pipeline:
93
93
  * 1. Complete an OAuth authorization-code return already on the URL (web)
94
- * 2. `runSessionColdBoot` — device-secret mint (+ native shared-key, or the
95
- * primary-identity-key lane in `sessionMode: 'identity'`)
94
+ * 2. `runSessionColdBoot` — device-secret mint (+ the native Commons-proof lane,
95
+ * or the primary-identity-key lane in `sessionMode: 'identity'`)
96
96
  *
97
97
  * Step 1 is ACCOUNT-MODE ONLY: it commits whichever account the IdP resolves,
98
98
  * which for an identity-bound client is somebody else's account by construction.
@@ -98,13 +98,12 @@ export const BenefitList: React.FC<BenefitListProps> = ({
98
98
  style,
99
99
  }) => (
100
100
  <Card
101
- variant="outlined"
102
101
  radius="radius-20"
103
102
  border="hairline"
104
103
  elevation="s"
105
104
  className={className}
106
105
  style={[{ padding: SPACING['space-16'], gap: SPACING['space-16'] }, style]}
107
- accessibilityLabel={accessibilityLabel}
106
+ accessibilityLabel={accessibilityLabel} appearance="outline"
108
107
  >
109
108
  {children}
110
109
  </Card>
@@ -19,7 +19,7 @@ const DEFAULT_FOLLOWED_ALL_LABEL = 'Following';
19
19
 
20
20
  /** Props shared by both single- and multi-user follow modes. */
21
21
  interface FollowButtonBaseProps {
22
- size?: 'small' | 'medium' | 'large';
22
+ size?: 'sm' | 'md' | 'lg';
23
23
  style?: StyleProp<ViewStyle>;
24
24
  textStyle?: StyleProp<TextStyle>;
25
25
  disabled?: boolean;
@@ -67,7 +67,7 @@ const FollowButtonInner = memo(function FollowButtonInner({
67
67
  oxyServices,
68
68
  initiallyFollowing,
69
69
  username,
70
- size = 'medium',
70
+ size = 'md',
71
71
  onFollowChange,
72
72
  style,
73
73
  textStyle,
@@ -140,7 +140,7 @@ const FollowButtonInner = memo(function FollowButtonInner({
140
140
  const FollowButtonMultiInner = memo(function FollowButtonMultiInner({
141
141
  userIds,
142
142
  initiallyAllFollowing = false,
143
- size = 'medium',
143
+ size = 'md',
144
144
  followAllLabel = DEFAULT_FOLLOW_ALL_LABEL,
145
145
  followedAllLabel = DEFAULT_FOLLOWED_ALL_LABEL,
146
146
  onFollowChange,
@@ -108,7 +108,7 @@ export interface FollowTargetButtonProps {
108
108
  verb?: FollowVerb;
109
109
  /** Full override, for a verb the vocabulary above does not carry. */
110
110
  labels?: Partial<FollowLabels>;
111
- size?: 'small' | 'medium' | 'large';
111
+ size?: 'sm' | 'md' | 'lg';
112
112
  style?: StyleProp<ViewStyle>;
113
113
  disabled?: boolean;
114
114
  /**
@@ -152,7 +152,7 @@ export const FollowTargetButton = memo(function FollowTargetButton({
152
152
  targetId,
153
153
  verb = 'follow',
154
154
  labels,
155
- size = 'medium',
155
+ size = 'md',
156
156
  style,
157
157
  disabled = false,
158
158
  showOptions = true,
@@ -309,7 +309,7 @@ export const FollowTargetButton = memo(function FollowTargetButton({
309
309
  <DropdownMenuTrigger asChild disabled={disabled || isUnknown}>
310
310
  <Button
311
311
  appearance="subtle" tone="support"
312
- size={size === 'large' ? 'large' : 'small'}
312
+ size={size === 'lg' ? 'lg' : 'sm'}
313
313
  icon={<ChevronDown width={16} />}
314
314
  disabled={disabled || isUnknown}
315
315
  accessibilityLabel={`${label} options`}
@@ -1,7 +1,7 @@
1
1
  import type React from 'react';
2
2
  import type { ViewStyle, TextStyle, StyleProp } from 'react-native';
3
3
  import { useTheme } from '@oxy.so/bloom/theme';
4
- import { Button } from '@oxy.so/bloom/button';
4
+ import { InverseButton } from '@oxy.so/bloom/button';
5
5
  import type { PaymentItem, PaymentGatewayResult } from '../screens/PaymentGatewayScreen';
6
6
  import { LogoIcon } from './logo/LogoIcon';
7
7
 
@@ -46,8 +46,7 @@ const PeableButton: React.FC<PeableButtonProps> = ({
46
46
  const textColor = variant === 'black' || (color && isColorDark(color)) ? theme.colors.background : '#1b1f0a';
47
47
 
48
48
  return (
49
- <Button
50
- variant="inverse"
49
+ <InverseButton
51
50
  onPress={handlePress}
52
51
  disabled={disabled}
53
52
  style={[{ backgroundColor, borderColor: textColor, borderWidth: 1 }, style]}
@@ -55,7 +54,7 @@ const PeableButton: React.FC<PeableButtonProps> = ({
55
54
  icon={<LogoIcon height={16} color={textColor} style={{ marginRight: 6 }} />}
56
55
  >
57
56
  {text}
58
- </Button>
57
+ </InverseButton>
59
58
  );
60
59
  };
61
60
 
@@ -12,7 +12,7 @@ export interface SurfaceHeaderActionProps {
12
12
 
13
13
  /** Header actions share Bloom's sizing, surface, disabled and loading behavior. */
14
14
  export const SurfaceHeaderAction: React.FC<SurfaceHeaderActionProps> = ({ label, onPress, loading, disabled }) => (
15
- <Button size="medium" onPress={onPress} loading={loading} disabled={disabled}>
15
+ <Button size="md" onPress={onPress} loading={loading} disabled={disabled}>
16
16
  {label}
17
17
  </Button>
18
18
  );
@@ -88,7 +88,7 @@ const errorStyles = StyleSheet.create({
88
88
  function ScreenPending() {
89
89
  return (
90
90
  <View style={errorStyles.container}>
91
- <Loading variant="spinner" size="large" />
91
+ <Loading variant="spinner" size="lg" />
92
92
  </View>
93
93
  );
94
94
  }
@@ -16,6 +16,7 @@ import {
16
16
  } from '../followButtonAccessibility';
17
17
 
18
18
  interface BloomFollowProps {
19
+ size?: 'sm' | 'md' | 'lg';
19
20
  following: boolean;
20
21
  label?: string;
21
22
  followingLabel?: string;
@@ -189,3 +190,11 @@ describe('FollowTargetButton names the state it shows', () => {
189
190
  expect(lastBloomProps()?.accessibilityLabel).toBe(label);
190
191
  });
191
192
  });
193
+
194
+
195
+ it.each(['sm', 'md', 'lg'] as const)('forwards canonical %s geometry in both follow modes', size => {
196
+ render(<FollowButton userId="nate-id" size={size} />);
197
+ expect(lastBloomProps()?.size).toBe(size);
198
+ render(<FollowButton userIds={['a', 'b']} size={size} />);
199
+ expect(lastBloomProps()?.size).toBe(size);
200
+ });
@@ -385,7 +385,7 @@ const AccountsMenuView: React.FC<AccountsMenuViewProps> = ({
385
385
  spanning the surface. */}
386
386
  <Button
387
387
  appearance="subtle" tone="neutral"
388
- size="small"
388
+ size="sm"
389
389
  onPress={handlers.onManage}
390
390
  accessibilityLabel={manageLabel}
391
391
  >
@@ -27,7 +27,7 @@ export const SubtleLink: React.FC<{
27
27
  testID?: string;
28
28
  }> = ({ label, onPress, disabled, testID }) => (
29
29
  <LinkButton
30
- variant="secondary"
30
+ linkTone="secondary"
31
31
  size="sm"
32
32
  onPress={onPress}
33
33
  disabled={disabled}
@@ -40,7 +40,7 @@ const ROUTE_GLYPH_SIZE = 44;
40
40
  */
41
41
  export const PreparingSurface: React.FC = () => {
42
42
  const { t } = useI18n();
43
- return <Loading variant="spinner" size="large" accessibilityLabel={t('common.status.loading')} />;
43
+ return <Loading variant="spinner" size="lg" accessibilityLabel={t('common.status.loading')} />;
44
44
  };
45
45
 
46
46
  /** The leading glyph for a route whose surface is elsewhere (the phone, Commons). */
@@ -214,13 +214,13 @@ const PaymentDetailsStep: React.FC<PaymentDetailsStepProps> = ({
214
214
  </View>
215
215
 
216
216
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
217
- <Button appearance="subtle" tone="neutral" onPress={onBack} size="small" icon={<Ionicons name="arrow-back" size={16} />}>
217
+ <Button appearance="subtle" tone="neutral" onPress={onBack} size="sm" icon={<Ionicons name="arrow-back" size={16} />}>
218
218
  {t('payment.actions.back')}
219
219
  </Button>
220
220
  <Button
221
221
  appearance="solid" tone="accent"
222
222
  onPress={onNext}
223
- size="small"
223
+ size="sm"
224
224
  icon={<Ionicons name="arrow-forward" size={16} />}
225
225
  iconPosition="right"
226
226
  disabled={paymentMethod === 'card' && !isCardValid}
@@ -77,10 +77,10 @@ const PaymentMethodStep: React.FC<PaymentMethodStepProps> = ({
77
77
  </View>
78
78
 
79
79
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
80
- <Button appearance="subtle" tone="neutral" onPress={onBack} size="small" icon={<Ionicons name="arrow-back" size={16} />}>
80
+ <Button appearance="subtle" tone="neutral" onPress={onBack} size="sm" icon={<Ionicons name="arrow-back" size={16} />}>
81
81
  {t('payment.actions.back')}
82
82
  </Button>
83
- <Button appearance="solid" tone="accent" onPress={onNext} size="small" icon={<Ionicons name="arrow-forward" size={16} />} iconPosition="right">
83
+ <Button appearance="solid" tone="accent" onPress={onNext} size="sm" icon={<Ionicons name="arrow-forward" size={16} />} iconPosition="right">
84
84
  {t('payment.actions.continue')}
85
85
  </Button>
86
86
  </View>
@@ -105,13 +105,13 @@ const PaymentReviewStep: React.FC<PaymentReviewStepProps> = ({
105
105
  </View>
106
106
 
107
107
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
108
- <Button appearance="subtle" tone="neutral" onPress={onBack} size="small" disabled={isPaying} icon={<Ionicons name="arrow-back" size={16} />}>
108
+ <Button appearance="subtle" tone="neutral" onPress={onBack} size="sm" disabled={isPaying} icon={<Ionicons name="arrow-back" size={16} />}>
109
109
  {t('payment.actions.back')}
110
110
  </Button>
111
111
  <Button
112
112
  appearance="solid" tone="accent"
113
113
  onPress={onPay}
114
- size="small"
114
+ size="sm"
115
115
  disabled={isPaying}
116
116
  icon={isPaying ? <ActivityIndicator size="small" color="#FFFFFF" /> : <Ionicons name="checkmark" size={16} />}
117
117
  iconPosition="right"
@@ -57,7 +57,7 @@ const PaymentSuccessStep: React.FC<PaymentSuccessStepProps> = ({
57
57
  </View>
58
58
  </View>
59
59
 
60
- <Button appearance="solid" tone="accent" onPress={onDone} size="small" icon={<Ionicons name="checkmark" size={16} />} iconPosition="right">
60
+ <Button appearance="solid" tone="accent" onPress={onDone} size="sm" icon={<Ionicons name="checkmark" size={16} />} iconPosition="right">
61
61
  {t('payment.actions.done')}
62
62
  </Button>
63
63
  </Animated.View>
@@ -145,10 +145,10 @@ const PaymentSummaryStep: React.FC<PaymentSummaryStepProps> = ({
145
145
  </View>
146
146
 
147
147
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
148
- <Button appearance="subtle" tone="neutral" onPress={onClose} size="small" icon={<Ionicons name="close" size={16} />}>
148
+ <Button appearance="subtle" tone="neutral" onPress={onClose} size="sm" icon={<Ionicons name="close" size={16} />}>
149
149
  {t('payment.actions.close')}
150
150
  </Button>
151
- <Button appearance="solid" tone="accent" onPress={onNext} size="small" icon={<Ionicons name="arrow-forward" size={16} />} iconPosition="right">
151
+ <Button appearance="solid" tone="accent" onPress={onNext} size="sm" icon={<Ionicons name="arrow-forward" size={16} />} iconPosition="right">
152
152
  {t('payment.actions.continue')}
153
153
  </Button>
154
154
  </View>
@@ -103,7 +103,7 @@ export const OxyAuthLoading: React.FC = () => {
103
103
  const { t } = useI18n();
104
104
  return (
105
105
  <View className="min-h-[300px] items-center justify-center">
106
- <Loading variant="spinner" size="large" accessibilityLabel={t('common.status.loading')} testID="oxy-auth-loading" />
106
+ <Loading variant="spinner" size="lg" accessibilityLabel={t('common.status.loading')} testID="oxy-auth-loading" />
107
107
  </View>
108
108
  );
109
109
  };
@@ -204,7 +204,7 @@ export const OxyLinkCommonsPanel: React.FC<OxyLinkCommonsPanelProps> = ({ onLink
204
204
  <OxyAuthScreen>
205
205
  <OxyAuthScreenHeader title={t('linkCommons.title')} description={t('linkCommons.subtitle')} />
206
206
  <View style={styles.plateRow}>
207
- <Loading variant="spinner" size="large" accessibilityLabel={t('common.status.loading')} />
207
+ <Loading variant="spinner" size="lg" accessibilityLabel={t('common.status.loading')} />
208
208
  </View>
209
209
  </OxyAuthScreen>
210
210
  );
@@ -95,7 +95,7 @@ export const OxyPasswordPanel: React.FC<OxyPasswordPanelProps> = ({ onDone, onCa
95
95
  {/* The field names the switch ("Sign out everywhere else, switch, off")
96
96
  and, on web, its label toggles it. One row: label, then the switch. */}
97
97
  <Field label={t('signInSecurity.password.signOutOthers')} style={styles.row}>
98
- <Switch value={signOutOthers} onValueChange={setSignOutOthers} testID="password-sign-out-others" />
98
+ <Switch checked={signOutOthers} onCheckedChange={setSignOutOthers} testID="password-sign-out-others" />
99
99
  </Field>
100
100
  </ReauthStep>
101
101
  );
@@ -72,7 +72,8 @@ export function ActionSheetSurface<T extends string>({
72
72
  {options.map((option) => (
73
73
  <Button
74
74
  key={option.value}
75
- variant={option.destructive ? 'destructive' : 'primary'}
75
+ appearance="solid"
76
+ tone={option.destructive ? 'danger' : 'accent'}
76
77
  onPress={() => surface.dismiss(option.value)}
77
78
  >
78
79
  {option.label}
@@ -291,7 +291,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
291
291
  <Text className="text-caption font-caption text-text-secondary px-space-4">
292
292
  {t('accounts.members.invite.roleLabel') || 'Role'}
293
293
  </Text>
294
- <SegmentedControl type="radio" label={t('accounts.members.invite.roleLabel') || 'Role'} value={inviteRole} onValueChange={setInviteRole} size="small">
294
+ <SegmentedControl type="radio" label={t('accounts.members.invite.roleLabel') || 'Role'} value={inviteRole} onValueChange={setInviteRole} size="sm">
295
295
  {ASSIGNABLE_ROLES.map(role => <SegmentedControlItem key={role} value={role}>
296
296
  <SegmentedControlItemText>{roleLabel(role)}</SegmentedControlItemText>
297
297
  </SegmentedControlItem>)}
@@ -372,7 +372,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
372
372
  {/* Role chips (editable) or static role label */}
373
373
  {canEditThisRole ? (
374
374
  <SegmentedControl type="radio" label={t('accounts.members.invite.roleLabel') || 'Role'}
375
- value={member.role} onValueChange={role => handleChangeRole(member, role)} disabled={updateMutation.isPending} size="small">
375
+ value={member.role} onValueChange={role => handleChangeRole(member, role)} disabled={updateMutation.isPending} size="sm">
376
376
  {ASSIGNABLE_ROLES.map(role => <SegmentedControlItem key={role} value={role}>
377
377
  <SegmentedControlItemText>{roleLabel(role)}</SegmentedControlItemText>
378
378
  </SegmentedControlItem>)}
@@ -387,7 +387,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
387
387
  {(canTransferToThis || canRemoveThisMember) ? (
388
388
  <View className="flex-row gap-space-16 pt-space-4">
389
389
  {canTransferToThis ? (
390
- <Button appearance="plain" tone="neutral" size="small"
390
+ <Button appearance="plain" tone="neutral" size="sm"
391
391
  accessibilityRole="button"
392
392
  accessibilityLabel={t('accounts.members.actions.transfer') || 'Transfer ownership'}
393
393
  onPress={() => confirmTransfer(member)}
@@ -400,7 +400,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
400
400
  </Button>
401
401
  ) : null}
402
402
  {canRemoveThisMember ? (
403
- <Button appearance="plain" tone="neutral" size="small"
403
+ <Button appearance="plain" tone="neutral" size="sm"
404
404
  accessibilityRole="button"
405
405
  accessibilityLabel={t('accounts.members.actions.remove') || 'Remove member'}
406
406
  onPress={() => confirmRemove(member)}
@@ -156,7 +156,7 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
156
156
 
157
157
  <Button
158
158
  appearance="solid" tone="accent"
159
- size="large"
159
+ size="lg"
160
160
  fullWidth
161
161
  className="mt-space-24"
162
162
  onPress={handleSubmit}
@@ -146,7 +146,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
146
146
  return (
147
147
  <View className="flex-1 bg-bg">
148
148
  {isLoading && !apps ? (
149
- <Loading size="large" color={bloomTheme.colors.primary} />
149
+ <Loading size="lg" color={bloomTheme.colors.primary} />
150
150
  ) : (
151
151
  <FlatList
152
152
  data={apps ?? []}
@@ -94,7 +94,7 @@ const DomainsScreen: React.FC<BaseScreenProps> = () => {
94
94
  };
95
95
 
96
96
  if (domains.isPending && isAuthenticated) {
97
- return <Loading size="large" color={bloomTheme.colors.primary} />;
97
+ return <Loading size="lg" color={bloomTheme.colors.primary} />;
98
98
  }
99
99
 
100
100
  return (
@@ -704,11 +704,10 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
704
704
  </TextField>
705
705
  </View>
706
706
  <Button
707
- variant="icon"
708
707
  onPress={handleAddItem}
709
708
  disabled={!newItemValue.trim()}
710
709
  accessibilityLabel={addLabel}
711
- icon={<Ionicons name="add" size={20} color={bloomTheme.colors.primaryForeground} />}
710
+ icon={<Ionicons name="add" size={20} color={bloomTheme.colors.primaryForeground} />} iconOnly tone="neutral" appearance="outline"
712
711
  />
713
712
  </View>
714
713
 
@@ -776,13 +776,13 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
776
776
  // Hide action buttons when selecting (in selectMode or bulk operations mode)
777
777
  rightElement: (!selectMode && selectedIds.size === 0) ? (
778
778
  <View className="flex-row items-center gap-1.5 ml-3">
779
- {(isImage || isVideo || file.contentType.includes('pdf')) ? <Button appearance="subtle" tone="neutral" size="small" iconOnly stopPropagation
779
+ {(isImage || isVideo || file.contentType.includes('pdf')) ? <Button appearance="subtle" tone="neutral" size="sm" iconOnly stopPropagation
780
780
  accessibilityLabel={`Preview ${file.filename}`} onPress={() => handleFileOpen(file)}
781
781
  icon={<Ionicons name="eye" size={18} color={colors.text} />} /> : null}
782
- <Button appearance="subtle" tone="neutral" size="small" iconOnly stopPropagation
782
+ <Button appearance="subtle" tone="neutral" size="sm" iconOnly stopPropagation
783
783
  accessibilityLabel={`Download ${file.filename}`} onPress={() => handleFileDownload(file.id, file.filename)}
784
784
  icon={<Ionicons name="download" size={18} color={colors.text} />} />
785
- <Button appearance="subtle" tone="danger" size="small" iconOnly stopPropagation loading={deletingId === file.id}
785
+ <Button appearance="subtle" tone="danger" size="sm" iconOnly stopPropagation loading={deletingId === file.id}
786
786
  accessibilityLabel={`Delete ${file.filename}`} onPress={() => confirmFileDelete(file.id, file.filename)}
787
787
  icon={<Ionicons name="trash" size={18} color={colors.error} />} />
788
788
  </View>
@@ -1144,7 +1144,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1144
1144
  style={{ maxWidth: '80%' }}
1145
1145
  >
1146
1146
  <SegmentedControl type="radio" label={t('fileManagement.viewMode') || 'File type'}
1147
- value={viewMode} onValueChange={setViewMode} size="small">
1147
+ value={viewMode} onValueChange={setViewMode} size="sm">
1148
1148
  {(['all', 'photos', 'videos', 'documents', 'audio'] as const).map(mode => (
1149
1149
  <SegmentedControlItem key={mode} value={mode} accessibilityLabel={mode}>
1150
1150
  <MaterialCommunityIcons
@@ -1154,7 +1154,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1154
1154
  ))}
1155
1155
  </SegmentedControl>
1156
1156
  </ScrollView>
1157
- <Button appearance="subtle" tone="neutral" size="small"
1157
+ <Button appearance="subtle" tone="neutral" size="sm"
1158
1158
  accessibilityRole="button"
1159
1159
  accessibilityLabel={t('fileManagement.a11y.sortBy', {
1160
1160
  field: sortBy,