@oxyhq/services 22.12.4 → 22.12.7

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 (639) hide show
  1. package/README.md +16 -46
  2. package/lib/commonjs/index.js +84 -10
  3. package/lib/commonjs/index.js.map +1 -1
  4. package/lib/commonjs/notifications/deviceNotifications.js +380 -0
  5. package/lib/commonjs/notifications/deviceNotifications.js.map +1 -0
  6. package/lib/commonjs/ui/boot/runProviderColdBoot.js +51 -9
  7. package/lib/commonjs/ui/boot/runProviderColdBoot.js.map +1 -1
  8. package/lib/commonjs/ui/client.js +0 -13
  9. package/lib/commonjs/ui/client.js.map +1 -1
  10. package/lib/commonjs/ui/components/AvatarCameraBadge.js +3 -2
  11. package/lib/commonjs/ui/components/AvatarCameraBadge.js.map +1 -1
  12. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +14 -3
  13. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
  14. package/lib/commonjs/ui/components/OxyAuthChooser.js +70 -1121
  15. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  16. package/lib/commonjs/ui/components/OxyConsentScreen.js +50 -12
  17. package/lib/commonjs/ui/components/OxyConsentScreen.js.map +1 -1
  18. package/lib/commonjs/ui/components/OxyProvider.js +4 -4
  19. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  20. package/lib/commonjs/ui/components/OxySignInButton.js +74 -40
  21. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  22. package/lib/commonjs/ui/components/OxySignInRequestSurface.js +147 -0
  23. package/lib/commonjs/ui/components/OxySignInRequestSurface.js.map +1 -0
  24. package/lib/commonjs/ui/components/ProfileButton.js +4 -3
  25. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  26. package/lib/commonjs/ui/components/SettingsIcon.js +3 -2
  27. package/lib/commonjs/ui/components/SettingsIcon.js.map +1 -1
  28. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +527 -0
  29. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -0
  30. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js +90 -0
  31. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js.map +1 -0
  32. package/lib/commonjs/ui/components/authChooser/SignInRequestView.js +106 -0
  33. package/lib/commonjs/ui/components/authChooser/SignInRequestView.js.map +1 -0
  34. package/lib/commonjs/ui/components/authChooser/SignUpView.js +188 -0
  35. package/lib/commonjs/ui/components/authChooser/SignUpView.js.map +1 -0
  36. package/lib/commonjs/ui/components/authChooser/TroubleDisclosure.js +61 -0
  37. package/lib/commonjs/ui/components/authChooser/TroubleDisclosure.js.map +1 -0
  38. package/lib/commonjs/ui/components/authChooser/primitives.js +170 -0
  39. package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -0
  40. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js +153 -0
  41. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js.map +1 -0
  42. package/lib/commonjs/ui/components/authChooser/signInProgress.js +54 -0
  43. package/lib/commonjs/ui/components/authChooser/signInProgress.js.map +1 -0
  44. package/lib/commonjs/ui/components/{oxyAuthChooserStyles.js → authChooser/styles.js} +19 -1
  45. package/lib/commonjs/ui/components/authChooser/styles.js.map +1 -0
  46. package/lib/commonjs/ui/components/authChooser/types.js +70 -0
  47. package/lib/commonjs/ui/components/authChooser/types.js.map +1 -0
  48. package/lib/commonjs/ui/components/authChooser/useUsernameAvailability.js +50 -0
  49. package/lib/commonjs/ui/components/authChooser/useUsernameAvailability.js.map +1 -0
  50. package/lib/commonjs/ui/components/fileManagement/AnimatedButton.js +3 -2
  51. package/lib/commonjs/ui/components/fileManagement/AnimatedButton.js.map +1 -1
  52. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +3 -2
  53. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  54. package/lib/commonjs/ui/components/fileManagement/FileViewer.js +15 -14
  55. package/lib/commonjs/ui/components/fileManagement/FileViewer.js.map +1 -1
  56. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +6 -5
  57. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
  58. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +3 -2
  59. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
  60. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +6 -6
  61. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  62. package/lib/commonjs/ui/components/payment/PaymentMethodStep.js +5 -5
  63. package/lib/commonjs/ui/components/payment/PaymentMethodStep.js.map +1 -1
  64. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js +10 -9
  65. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js.map +1 -1
  66. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js +4 -3
  67. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  68. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js +6 -5
  69. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  70. package/lib/commonjs/ui/context/OxyContext.js +200 -29
  71. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  72. package/lib/commonjs/ui/context/commitSessionFlow.js +43 -0
  73. package/lib/commonjs/ui/context/commitSessionFlow.js.map +1 -1
  74. package/lib/commonjs/ui/context/useOxyAccountGraph.js +13 -5
  75. package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
  76. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +6 -1
  77. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -1
  78. package/lib/commonjs/ui/index.js +0 -13
  79. package/lib/commonjs/ui/index.js.map +1 -1
  80. package/lib/commonjs/ui/oauth/browserAuthTransport.js +168 -0
  81. package/lib/commonjs/ui/oauth/browserAuthTransport.js.map +1 -0
  82. package/lib/commonjs/ui/oauth/completeOAuthCode.js +78 -0
  83. package/lib/commonjs/ui/oauth/completeOAuthCode.js.map +1 -0
  84. package/lib/commonjs/ui/oauth/legacyRedirectLanes.js +48 -0
  85. package/lib/commonjs/ui/oauth/legacyRedirectLanes.js.map +1 -0
  86. package/lib/commonjs/ui/oauth/oauthHandshake.js +53 -0
  87. package/lib/commonjs/ui/oauth/oauthHandshake.js.map +1 -0
  88. package/lib/commonjs/ui/oauth/oauthPopup.js +229 -0
  89. package/lib/commonjs/ui/oauth/oauthPopup.js.map +1 -0
  90. package/lib/commonjs/ui/oauth/oauthPopupMessages.js +141 -0
  91. package/lib/commonjs/ui/oauth/oauthPopupMessages.js.map +1 -0
  92. package/lib/commonjs/ui/oauth/types.js +2 -0
  93. package/lib/commonjs/ui/oauth/types.js.map +1 -0
  94. package/lib/commonjs/ui/screens/AccountMembersScreen.js +4 -3
  95. package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
  96. package/lib/commonjs/ui/screens/CreateAccountScreen.js +7 -6
  97. package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
  98. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +4 -3
  99. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  100. package/lib/commonjs/ui/screens/FAQScreen.js +3 -2
  101. package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
  102. package/lib/commonjs/ui/screens/FeedbackScreen.js +11 -10
  103. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  104. package/lib/commonjs/ui/screens/FileManagementScreen.js +19 -18
  105. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  106. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +4 -3
  107. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  108. package/lib/commonjs/ui/screens/ManageAccountScreen.js +2 -2
  109. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  110. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +3 -3
  111. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  112. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +9 -8
  113. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  114. package/lib/commonjs/ui/screens/ProfileScreen.js +10 -10
  115. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  116. package/lib/commonjs/ui/screens/UserListScreen.js +3 -3
  117. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  118. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +3 -2
  119. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  120. package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js +4 -3
  121. package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js.map +1 -1
  122. package/lib/commonjs/ui/screens/fileManagement/FileListSection.js +4 -3
  123. package/lib/commonjs/ui/screens/fileManagement/FileListSection.js.map +1 -1
  124. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +4 -3
  125. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  126. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js +3 -2
  127. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js.map +1 -1
  128. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +3 -2
  129. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  130. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +4 -3
  131. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  132. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +4 -3
  133. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  134. package/lib/commonjs/ui/server.js +2 -5
  135. package/lib/commonjs/ui/server.js.map +1 -1
  136. package/lib/commonjs/ui/session/authStore.js +6 -75
  137. package/lib/commonjs/ui/session/authStore.js.map +1 -1
  138. package/lib/commonjs/ui/session/createSessionClient.js +11 -3
  139. package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
  140. package/lib/commonjs/ui/session/identityBinding.js +95 -0
  141. package/lib/commonjs/ui/session/identityBinding.js.map +1 -0
  142. package/lib/commonjs/ui/session/index.js +13 -0
  143. package/lib/commonjs/ui/session/index.js.map +1 -1
  144. package/lib/commonjs/ui/session/nativeSecureStorage.js +90 -0
  145. package/lib/commonjs/ui/session/nativeSecureStorage.js.map +1 -0
  146. package/lib/commonjs/ui/session/tokenTransport.js +11 -1
  147. package/lib/commonjs/ui/session/tokenTransport.js.map +1 -1
  148. package/lib/commonjs/ui/utils/crossOriginRestore.js +3 -2
  149. package/lib/commonjs/ui/utils/crossOriginRestore.js.map +1 -1
  150. package/lib/commonjs/ui/utils/deliveryPlatform.js +58 -0
  151. package/lib/commonjs/ui/utils/deliveryPlatform.js.map +1 -0
  152. package/lib/commonjs/ui/utils/oauthReturn.js +70 -46
  153. package/lib/commonjs/ui/utils/oauthReturn.js.map +1 -1
  154. package/lib/module/index.js +27 -4
  155. package/lib/module/index.js.map +1 -1
  156. package/lib/module/notifications/deviceNotifications.js +371 -0
  157. package/lib/module/notifications/deviceNotifications.js.map +1 -0
  158. package/lib/module/ui/boot/runProviderColdBoot.js +51 -9
  159. package/lib/module/ui/boot/runProviderColdBoot.js.map +1 -1
  160. package/lib/module/ui/client.js +0 -1
  161. package/lib/module/ui/client.js.map +1 -1
  162. package/lib/module/ui/components/AvatarCameraBadge.js +1 -1
  163. package/lib/module/ui/components/AvatarCameraBadge.js.map +1 -1
  164. package/lib/module/ui/components/OxyAccountDialogScreen.js +14 -3
  165. package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
  166. package/lib/module/ui/components/OxyAuthChooser.js +74 -1126
  167. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  168. package/lib/module/ui/components/OxyConsentScreen.js +50 -12
  169. package/lib/module/ui/components/OxyConsentScreen.js.map +1 -1
  170. package/lib/module/ui/components/OxyProvider.js +4 -4
  171. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  172. package/lib/module/ui/components/OxySignInButton.js +76 -42
  173. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  174. package/lib/module/ui/components/OxySignInRequestSurface.js +141 -0
  175. package/lib/module/ui/components/OxySignInRequestSurface.js.map +1 -0
  176. package/lib/module/ui/components/ProfileButton.js +1 -1
  177. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  178. package/lib/module/ui/components/SettingsIcon.js +1 -1
  179. package/lib/module/ui/components/SettingsIcon.js.map +1 -1
  180. package/lib/module/ui/components/authChooser/AccountsMenuView.js +523 -0
  181. package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -0
  182. package/lib/module/ui/components/authChooser/SignInEntryView.js +85 -0
  183. package/lib/module/ui/components/authChooser/SignInEntryView.js.map +1 -0
  184. package/lib/module/ui/components/authChooser/SignInRequestView.js +101 -0
  185. package/lib/module/ui/components/authChooser/SignInRequestView.js.map +1 -0
  186. package/lib/module/ui/components/authChooser/SignUpView.js +184 -0
  187. package/lib/module/ui/components/authChooser/SignUpView.js.map +1 -0
  188. package/lib/module/ui/components/authChooser/TroubleDisclosure.js +57 -0
  189. package/lib/module/ui/components/authChooser/TroubleDisclosure.js.map +1 -0
  190. package/lib/module/ui/components/authChooser/primitives.js +163 -0
  191. package/lib/module/ui/components/authChooser/primitives.js.map +1 -0
  192. package/lib/module/ui/components/authChooser/requestSurfaces.js +143 -0
  193. package/lib/module/ui/components/authChooser/requestSurfaces.js.map +1 -0
  194. package/lib/module/ui/components/authChooser/signInProgress.js +50 -0
  195. package/lib/module/ui/components/authChooser/signInProgress.js.map +1 -0
  196. package/lib/module/ui/components/{oxyAuthChooserStyles.js → authChooser/styles.js} +19 -1
  197. package/lib/module/ui/components/authChooser/styles.js.map +1 -0
  198. package/lib/module/ui/components/authChooser/types.js +66 -0
  199. package/lib/module/ui/components/authChooser/types.js.map +1 -0
  200. package/lib/module/ui/components/authChooser/useUsernameAvailability.js +46 -0
  201. package/lib/module/ui/components/authChooser/useUsernameAvailability.js.map +1 -0
  202. package/lib/module/ui/components/fileManagement/AnimatedButton.js +1 -1
  203. package/lib/module/ui/components/fileManagement/AnimatedButton.js.map +1 -1
  204. package/lib/module/ui/components/fileManagement/FileDetailsModal.js +1 -1
  205. package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  206. package/lib/module/ui/components/fileManagement/FileViewer.js +1 -1
  207. package/lib/module/ui/components/fileManagement/FileViewer.js.map +1 -1
  208. package/lib/module/ui/components/fileManagement/UploadPreview.js +1 -1
  209. package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
  210. package/lib/module/ui/components/modals/DeleteAccountModal.js +1 -1
  211. package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
  212. package/lib/module/ui/components/payment/PaymentDetailsStep.js +1 -1
  213. package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  214. package/lib/module/ui/components/payment/PaymentMethodStep.js +1 -1
  215. package/lib/module/ui/components/payment/PaymentMethodStep.js.map +1 -1
  216. package/lib/module/ui/components/payment/PaymentReviewStep.js +1 -1
  217. package/lib/module/ui/components/payment/PaymentReviewStep.js.map +1 -1
  218. package/lib/module/ui/components/payment/PaymentSuccessStep.js +1 -1
  219. package/lib/module/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  220. package/lib/module/ui/components/payment/PaymentSummaryStep.js +1 -1
  221. package/lib/module/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  222. package/lib/module/ui/context/OxyContext.js +203 -32
  223. package/lib/module/ui/context/OxyContext.js.map +1 -1
  224. package/lib/module/ui/context/commitSessionFlow.js +42 -0
  225. package/lib/module/ui/context/commitSessionFlow.js.map +1 -1
  226. package/lib/module/ui/context/useOxyAccountGraph.js +13 -5
  227. package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
  228. package/lib/module/ui/hooks/useSwitchableAccounts.js +6 -1
  229. package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -1
  230. package/lib/module/ui/index.js +0 -1
  231. package/lib/module/ui/index.js.map +1 -1
  232. package/lib/module/ui/oauth/browserAuthTransport.js +165 -0
  233. package/lib/module/ui/oauth/browserAuthTransport.js.map +1 -0
  234. package/lib/module/ui/oauth/completeOAuthCode.js +75 -0
  235. package/lib/module/ui/oauth/completeOAuthCode.js.map +1 -0
  236. package/lib/module/ui/oauth/legacyRedirectLanes.js +44 -0
  237. package/lib/module/ui/oauth/legacyRedirectLanes.js.map +1 -0
  238. package/lib/module/ui/oauth/oauthHandshake.js +50 -0
  239. package/lib/module/ui/oauth/oauthHandshake.js.map +1 -0
  240. package/lib/module/ui/oauth/oauthPopup.js +221 -0
  241. package/lib/module/ui/oauth/oauthPopup.js.map +1 -0
  242. package/lib/module/ui/oauth/oauthPopupMessages.js +135 -0
  243. package/lib/module/ui/oauth/oauthPopupMessages.js.map +1 -0
  244. package/lib/module/ui/oauth/types.js +2 -0
  245. package/lib/module/ui/oauth/types.js.map +1 -0
  246. package/lib/module/ui/screens/AccountMembersScreen.js +1 -1
  247. package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
  248. package/lib/module/ui/screens/CreateAccountScreen.js +1 -1
  249. package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
  250. package/lib/module/ui/screens/EditProfileFieldScreen.js +1 -1
  251. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  252. package/lib/module/ui/screens/FAQScreen.js +1 -1
  253. package/lib/module/ui/screens/FAQScreen.js.map +1 -1
  254. package/lib/module/ui/screens/FeedbackScreen.js +1 -1
  255. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  256. package/lib/module/ui/screens/FileManagementScreen.js +2 -1
  257. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  258. package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -1
  259. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  260. package/lib/module/ui/screens/ManageAccountScreen.js +1 -1
  261. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  262. package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
  263. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  264. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +1 -1
  265. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  266. package/lib/module/ui/screens/ProfileScreen.js +1 -1
  267. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  268. package/lib/module/ui/screens/UserListScreen.js +1 -1
  269. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  270. package/lib/module/ui/screens/WelcomeNewUserScreen.js +1 -1
  271. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  272. package/lib/module/ui/screens/fileManagement/FileLibraryError.js +1 -1
  273. package/lib/module/ui/screens/fileManagement/FileLibraryError.js.map +1 -1
  274. package/lib/module/ui/screens/fileManagement/FileListSection.js +1 -1
  275. package/lib/module/ui/screens/fileManagement/FileListSection.js.map +1 -1
  276. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +2 -1
  277. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  278. package/lib/module/ui/screens/fileManagement/UploadBar.js +1 -1
  279. package/lib/module/ui/screens/fileManagement/UploadBar.js.map +1 -1
  280. package/lib/module/ui/screens/trust/TrustCenterScreen.js +1 -1
  281. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  282. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +1 -1
  283. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  284. package/lib/module/ui/screens/trust/TrustRewardsScreen.js +1 -1
  285. package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  286. package/lib/module/ui/server.js +0 -2
  287. package/lib/module/ui/server.js.map +1 -1
  288. package/lib/module/ui/session/authStore.js +5 -75
  289. package/lib/module/ui/session/authStore.js.map +1 -1
  290. package/lib/module/ui/session/createSessionClient.js +11 -3
  291. package/lib/module/ui/session/createSessionClient.js.map +1 -1
  292. package/lib/module/ui/session/identityBinding.js +89 -0
  293. package/lib/module/ui/session/identityBinding.js.map +1 -0
  294. package/lib/module/ui/session/index.js +5 -2
  295. package/lib/module/ui/session/index.js.map +1 -1
  296. package/lib/module/ui/session/nativeSecureStorage.js +88 -0
  297. package/lib/module/ui/session/nativeSecureStorage.js.map +1 -0
  298. package/lib/module/ui/session/tokenTransport.js +11 -1
  299. package/lib/module/ui/session/tokenTransport.js.map +1 -1
  300. package/lib/module/ui/utils/crossOriginRestore.js +4 -3
  301. package/lib/module/ui/utils/crossOriginRestore.js.map +1 -1
  302. package/lib/module/ui/utils/deliveryPlatform.js +55 -0
  303. package/lib/module/ui/utils/deliveryPlatform.js.map +1 -0
  304. package/lib/module/ui/utils/oauthReturn.js +70 -46
  305. package/lib/module/ui/utils/oauthReturn.js.map +1 -1
  306. package/lib/typescript/commonjs/index.d.ts +9 -1
  307. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  308. package/lib/typescript/commonjs/notifications/deviceNotifications.d.ts +141 -0
  309. package/lib/typescript/commonjs/notifications/deviceNotifications.d.ts.map +1 -0
  310. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts +34 -2
  311. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  312. package/lib/typescript/commonjs/ui/client.d.ts +0 -1
  313. package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
  314. package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  315. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +16 -29
  316. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  317. package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts.map +1 -1
  318. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  319. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +17 -12
  320. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  321. package/lib/typescript/commonjs/ui/components/OxySignInRequestSurface.d.ts +108 -0
  322. package/lib/typescript/commonjs/ui/components/OxySignInRequestSurface.d.ts.map +1 -0
  323. package/lib/typescript/commonjs/ui/components/SettingsIcon.d.ts +1 -1
  324. package/lib/typescript/commonjs/ui/components/SettingsIcon.d.ts.map +1 -1
  325. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts +38 -0
  326. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -0
  327. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts +32 -0
  328. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts.map +1 -0
  329. package/lib/typescript/commonjs/ui/components/authChooser/SignInRequestView.d.ts +34 -0
  330. package/lib/typescript/commonjs/ui/components/authChooser/SignInRequestView.d.ts.map +1 -0
  331. package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts +34 -0
  332. package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts.map +1 -0
  333. package/lib/typescript/commonjs/ui/components/authChooser/TroubleDisclosure.d.ts +36 -0
  334. package/lib/typescript/commonjs/ui/components/authChooser/TroubleDisclosure.d.ts.map +1 -0
  335. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +55 -0
  336. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -0
  337. package/lib/typescript/commonjs/ui/components/authChooser/requestSurfaces.d.ts +58 -0
  338. package/lib/typescript/commonjs/ui/components/authChooser/requestSurfaces.d.ts.map +1 -0
  339. package/lib/typescript/commonjs/ui/components/authChooser/signInProgress.d.ts +26 -0
  340. package/lib/typescript/commonjs/ui/components/authChooser/signInProgress.d.ts.map +1 -0
  341. package/lib/typescript/{module/ui/components/oxyAuthChooserStyles.d.ts → commonjs/ui/components/authChooser/styles.d.ts} +19 -1
  342. package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts.map +1 -0
  343. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +103 -0
  344. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts.map +1 -0
  345. package/lib/typescript/commonjs/ui/components/authChooser/useUsernameAvailability.d.ts +16 -0
  346. package/lib/typescript/commonjs/ui/components/authChooser/useUsernameAvailability.d.ts.map +1 -0
  347. package/lib/typescript/commonjs/ui/components/payment/types.d.ts +1 -1
  348. package/lib/typescript/commonjs/ui/components/payment/types.d.ts.map +1 -1
  349. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  350. package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts +40 -0
  351. package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts.map +1 -1
  352. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +44 -1
  353. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
  354. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts +7 -1
  355. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  356. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
  357. package/lib/typescript/commonjs/ui/index.d.ts +0 -1
  358. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  359. package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts +56 -0
  360. package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts.map +1 -0
  361. package/lib/typescript/commonjs/ui/oauth/completeOAuthCode.d.ts +49 -0
  362. package/lib/typescript/commonjs/ui/oauth/completeOAuthCode.d.ts.map +1 -0
  363. package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts +40 -0
  364. package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts.map +1 -0
  365. package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts +50 -0
  366. package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts.map +1 -0
  367. package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts +77 -0
  368. package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts.map +1 -0
  369. package/lib/typescript/commonjs/ui/oauth/oauthPopupMessages.d.ts +67 -0
  370. package/lib/typescript/commonjs/ui/oauth/oauthPopupMessages.d.ts.map +1 -0
  371. package/lib/typescript/commonjs/ui/oauth/types.d.ts +176 -0
  372. package/lib/typescript/commonjs/ui/oauth/types.d.ts.map +1 -0
  373. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
  374. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  375. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  376. package/lib/typescript/commonjs/ui/server.d.ts +0 -2
  377. package/lib/typescript/commonjs/ui/server.d.ts.map +1 -1
  378. package/lib/typescript/commonjs/ui/session/authStore.d.ts +3 -7
  379. package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
  380. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +8 -1
  381. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
  382. package/lib/typescript/commonjs/ui/session/identityBinding.d.ts +66 -0
  383. package/lib/typescript/commonjs/ui/session/identityBinding.d.ts.map +1 -0
  384. package/lib/typescript/commonjs/ui/session/index.d.ts +6 -2
  385. package/lib/typescript/commonjs/ui/session/index.d.ts.map +1 -1
  386. package/lib/typescript/commonjs/ui/session/nativeSecureStorage.d.ts +25 -0
  387. package/lib/typescript/commonjs/ui/session/nativeSecureStorage.d.ts.map +1 -0
  388. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts +8 -1
  389. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts.map +1 -1
  390. package/lib/typescript/commonjs/ui/types/navigation.d.ts +44 -0
  391. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  392. package/lib/typescript/commonjs/ui/utils/crossOriginRestore.d.ts.map +1 -1
  393. package/lib/typescript/commonjs/ui/utils/deliveryPlatform.d.ts +33 -0
  394. package/lib/typescript/commonjs/ui/utils/deliveryPlatform.d.ts.map +1 -0
  395. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +1 -1
  396. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
  397. package/lib/typescript/commonjs/ui/utils/oauthReturn.d.ts +30 -16
  398. package/lib/typescript/commonjs/ui/utils/oauthReturn.d.ts.map +1 -1
  399. package/lib/typescript/module/index.d.ts +9 -1
  400. package/lib/typescript/module/index.d.ts.map +1 -1
  401. package/lib/typescript/module/notifications/deviceNotifications.d.ts +141 -0
  402. package/lib/typescript/module/notifications/deviceNotifications.d.ts.map +1 -0
  403. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts +34 -2
  404. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  405. package/lib/typescript/module/ui/client.d.ts +0 -1
  406. package/lib/typescript/module/ui/client.d.ts.map +1 -1
  407. package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  408. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +16 -29
  409. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  410. package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts.map +1 -1
  411. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  412. package/lib/typescript/module/ui/components/OxySignInButton.d.ts +17 -12
  413. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  414. package/lib/typescript/module/ui/components/OxySignInRequestSurface.d.ts +108 -0
  415. package/lib/typescript/module/ui/components/OxySignInRequestSurface.d.ts.map +1 -0
  416. package/lib/typescript/module/ui/components/SettingsIcon.d.ts +1 -1
  417. package/lib/typescript/module/ui/components/SettingsIcon.d.ts.map +1 -1
  418. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts +38 -0
  419. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -0
  420. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts +32 -0
  421. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts.map +1 -0
  422. package/lib/typescript/module/ui/components/authChooser/SignInRequestView.d.ts +34 -0
  423. package/lib/typescript/module/ui/components/authChooser/SignInRequestView.d.ts.map +1 -0
  424. package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts +34 -0
  425. package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts.map +1 -0
  426. package/lib/typescript/module/ui/components/authChooser/TroubleDisclosure.d.ts +36 -0
  427. package/lib/typescript/module/ui/components/authChooser/TroubleDisclosure.d.ts.map +1 -0
  428. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +55 -0
  429. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -0
  430. package/lib/typescript/module/ui/components/authChooser/requestSurfaces.d.ts +58 -0
  431. package/lib/typescript/module/ui/components/authChooser/requestSurfaces.d.ts.map +1 -0
  432. package/lib/typescript/module/ui/components/authChooser/signInProgress.d.ts +26 -0
  433. package/lib/typescript/module/ui/components/authChooser/signInProgress.d.ts.map +1 -0
  434. package/lib/typescript/{commonjs/ui/components/oxyAuthChooserStyles.d.ts → module/ui/components/authChooser/styles.d.ts} +19 -1
  435. package/lib/typescript/module/ui/components/authChooser/styles.d.ts.map +1 -0
  436. package/lib/typescript/module/ui/components/authChooser/types.d.ts +103 -0
  437. package/lib/typescript/module/ui/components/authChooser/types.d.ts.map +1 -0
  438. package/lib/typescript/module/ui/components/authChooser/useUsernameAvailability.d.ts +16 -0
  439. package/lib/typescript/module/ui/components/authChooser/useUsernameAvailability.d.ts.map +1 -0
  440. package/lib/typescript/module/ui/components/payment/types.d.ts +1 -1
  441. package/lib/typescript/module/ui/components/payment/types.d.ts.map +1 -1
  442. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  443. package/lib/typescript/module/ui/context/commitSessionFlow.d.ts +40 -0
  444. package/lib/typescript/module/ui/context/commitSessionFlow.d.ts.map +1 -1
  445. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +44 -1
  446. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
  447. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts +7 -1
  448. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  449. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
  450. package/lib/typescript/module/ui/index.d.ts +0 -1
  451. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  452. package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts +56 -0
  453. package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts.map +1 -0
  454. package/lib/typescript/module/ui/oauth/completeOAuthCode.d.ts +49 -0
  455. package/lib/typescript/module/ui/oauth/completeOAuthCode.d.ts.map +1 -0
  456. package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts +40 -0
  457. package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts.map +1 -0
  458. package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts +50 -0
  459. package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts.map +1 -0
  460. package/lib/typescript/module/ui/oauth/oauthPopup.d.ts +77 -0
  461. package/lib/typescript/module/ui/oauth/oauthPopup.d.ts.map +1 -0
  462. package/lib/typescript/module/ui/oauth/oauthPopupMessages.d.ts +67 -0
  463. package/lib/typescript/module/ui/oauth/oauthPopupMessages.d.ts.map +1 -0
  464. package/lib/typescript/module/ui/oauth/types.d.ts +176 -0
  465. package/lib/typescript/module/ui/oauth/types.d.ts.map +1 -0
  466. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
  467. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  468. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  469. package/lib/typescript/module/ui/server.d.ts +0 -2
  470. package/lib/typescript/module/ui/server.d.ts.map +1 -1
  471. package/lib/typescript/module/ui/session/authStore.d.ts +3 -7
  472. package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
  473. package/lib/typescript/module/ui/session/createSessionClient.d.ts +8 -1
  474. package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
  475. package/lib/typescript/module/ui/session/identityBinding.d.ts +66 -0
  476. package/lib/typescript/module/ui/session/identityBinding.d.ts.map +1 -0
  477. package/lib/typescript/module/ui/session/index.d.ts +6 -2
  478. package/lib/typescript/module/ui/session/index.d.ts.map +1 -1
  479. package/lib/typescript/module/ui/session/nativeSecureStorage.d.ts +25 -0
  480. package/lib/typescript/module/ui/session/nativeSecureStorage.d.ts.map +1 -0
  481. package/lib/typescript/module/ui/session/tokenTransport.d.ts +8 -1
  482. package/lib/typescript/module/ui/session/tokenTransport.d.ts.map +1 -1
  483. package/lib/typescript/module/ui/types/navigation.d.ts +44 -0
  484. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  485. package/lib/typescript/module/ui/utils/crossOriginRestore.d.ts.map +1 -1
  486. package/lib/typescript/module/ui/utils/deliveryPlatform.d.ts +33 -0
  487. package/lib/typescript/module/ui/utils/deliveryPlatform.d.ts.map +1 -0
  488. package/lib/typescript/module/ui/utils/fileManagement.d.ts +1 -1
  489. package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
  490. package/lib/typescript/module/ui/utils/oauthReturn.d.ts +30 -16
  491. package/lib/typescript/module/ui/utils/oauthReturn.d.ts.map +1 -1
  492. package/package.json +15 -7
  493. package/src/index.ts +50 -5
  494. package/src/notifications/deviceNotifications.ts +395 -0
  495. package/src/ui/boot/__tests__/coldBootWebAuthMode.test.ts +281 -0
  496. package/src/ui/boot/runProviderColdBoot.ts +83 -13
  497. package/src/ui/client.ts +0 -1
  498. package/src/ui/components/AvatarCameraBadge.tsx +1 -1
  499. package/src/ui/components/OxyAccountDialogScreen.tsx +20 -3
  500. package/src/ui/components/OxyAuthChooser.tsx +91 -1230
  501. package/src/ui/components/OxyConsentScreen.tsx +56 -13
  502. package/src/ui/components/OxyProvider.tsx +4 -4
  503. package/src/ui/components/OxySignInButton.tsx +119 -78
  504. package/src/ui/components/OxySignInRequestSurface.tsx +202 -0
  505. package/src/ui/components/ProfileButton.tsx +1 -1
  506. package/src/ui/components/SettingsIcon.tsx +1 -1
  507. package/src/ui/components/__tests__/OxyConsentScreen.test.tsx +27 -0
  508. package/src/ui/components/authChooser/AccountsMenuView.tsx +569 -0
  509. package/src/ui/components/authChooser/SignInEntryView.tsx +121 -0
  510. package/src/ui/components/authChooser/SignInRequestView.tsx +130 -0
  511. package/src/ui/components/authChooser/SignUpView.tsx +174 -0
  512. package/src/ui/components/authChooser/TroubleDisclosure.tsx +73 -0
  513. package/src/ui/components/authChooser/primitives.tsx +144 -0
  514. package/src/ui/components/authChooser/requestSurfaces.tsx +120 -0
  515. package/src/ui/components/authChooser/signInProgress.ts +54 -0
  516. package/src/ui/components/{oxyAuthChooserStyles.ts → authChooser/styles.ts} +18 -0
  517. package/src/ui/components/authChooser/types.ts +120 -0
  518. package/src/ui/components/authChooser/useUsernameAvailability.ts +60 -0
  519. package/src/ui/components/fileManagement/AnimatedButton.tsx +1 -1
  520. package/src/ui/components/fileManagement/FileDetailsModal.tsx +1 -1
  521. package/src/ui/components/fileManagement/FileViewer.tsx +1 -1
  522. package/src/ui/components/fileManagement/UploadPreview.tsx +1 -1
  523. package/src/ui/components/modals/DeleteAccountModal.tsx +1 -1
  524. package/src/ui/components/payment/PaymentDetailsStep.tsx +1 -1
  525. package/src/ui/components/payment/PaymentMethodStep.tsx +1 -1
  526. package/src/ui/components/payment/PaymentReviewStep.tsx +1 -1
  527. package/src/ui/components/payment/PaymentSuccessStep.tsx +1 -1
  528. package/src/ui/components/payment/PaymentSummaryStep.tsx +1 -1
  529. package/src/ui/components/payment/types.ts +1 -1
  530. package/src/ui/context/OxyContext.tsx +220 -24
  531. package/src/ui/context/__tests__/commitSessionFlow.test.ts +89 -0
  532. package/src/ui/context/commitSessionFlow.ts +61 -0
  533. package/src/ui/context/oxyContextTypes.ts +45 -1
  534. package/src/ui/context/useOxyAccountGraph.ts +19 -5
  535. package/src/ui/hooks/useSwitchableAccounts.ts +12 -1
  536. package/src/ui/index.ts +0 -1
  537. package/src/ui/oauth/__tests__/browserAuthTransport.test.ts +335 -0
  538. package/src/ui/oauth/__tests__/completeOAuthCode.test.ts +142 -0
  539. package/src/ui/oauth/__tests__/oauthPopup.test.ts +326 -0
  540. package/src/ui/oauth/__tests__/oauthPopupMessages.test.ts +189 -0
  541. package/src/ui/oauth/__tests__/sharedCompletionPath.test.ts +174 -0
  542. package/src/ui/oauth/browserAuthTransport.ts +187 -0
  543. package/src/ui/oauth/completeOAuthCode.ts +93 -0
  544. package/src/ui/oauth/legacyRedirectLanes.ts +43 -0
  545. package/src/ui/oauth/oauthHandshake.ts +74 -0
  546. package/src/ui/oauth/oauthPopup.ts +219 -0
  547. package/src/ui/oauth/oauthPopupMessages.ts +136 -0
  548. package/src/ui/oauth/types.ts +150 -0
  549. package/src/ui/screens/AccountMembersScreen.tsx +1 -1
  550. package/src/ui/screens/CreateAccountScreen.tsx +1 -1
  551. package/src/ui/screens/EditProfileFieldScreen.tsx +1 -1
  552. package/src/ui/screens/FAQScreen.tsx +1 -1
  553. package/src/ui/screens/FeedbackScreen.tsx +2 -1
  554. package/src/ui/screens/FileManagementScreen.tsx +2 -1
  555. package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
  556. package/src/ui/screens/ManageAccountScreen.tsx +1 -1
  557. package/src/ui/screens/PaymentGatewayScreen.tsx +1 -1
  558. package/src/ui/screens/PremiumSubscriptionScreen.tsx +1 -1
  559. package/src/ui/screens/ProfileScreen.tsx +1 -1
  560. package/src/ui/screens/UserListScreen.tsx +1 -1
  561. package/src/ui/screens/WelcomeNewUserScreen.tsx +1 -1
  562. package/src/ui/screens/fileManagement/FileLibraryError.tsx +1 -1
  563. package/src/ui/screens/fileManagement/FileListSection.tsx +1 -1
  564. package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +2 -1
  565. package/src/ui/screens/fileManagement/UploadBar.tsx +1 -1
  566. package/src/ui/screens/trust/TrustCenterScreen.tsx +1 -1
  567. package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +1 -1
  568. package/src/ui/screens/trust/TrustRewardsScreen.tsx +1 -1
  569. package/src/ui/server.ts +0 -2
  570. package/src/ui/session/__tests__/createSessionClient.test.ts +26 -0
  571. package/src/ui/session/__tests__/tokenTransport.test.ts +34 -0
  572. package/src/ui/session/authStore.ts +5 -89
  573. package/src/ui/session/createSessionClient.ts +15 -2
  574. package/src/ui/session/identityBinding.ts +116 -0
  575. package/src/ui/session/index.ts +6 -2
  576. package/src/ui/session/nativeSecureStorage.ts +98 -0
  577. package/src/ui/session/tokenTransport.ts +14 -1
  578. package/src/ui/types/navigation.ts +44 -1
  579. package/src/ui/utils/crossOriginRestore.ts +4 -7
  580. package/src/ui/utils/deliveryPlatform.ts +65 -0
  581. package/src/ui/utils/fileManagement.ts +1 -1
  582. package/src/ui/utils/oauthReturn.ts +74 -65
  583. package/lib/commonjs/assets/assets/fonts/Inter/Inter_18pt-Black.ttf +0 -0
  584. package/lib/commonjs/assets/assets/fonts/Inter/Inter_18pt-Bold.ttf +0 -0
  585. package/lib/commonjs/assets/assets/fonts/Inter/Inter_18pt-ExtraBold.ttf +0 -0
  586. package/lib/commonjs/assets/assets/fonts/Inter/Inter_18pt-Light.ttf +0 -0
  587. package/lib/commonjs/assets/assets/fonts/Inter/Inter_18pt-Medium.ttf +0 -0
  588. package/lib/commonjs/assets/assets/fonts/Inter/Inter_18pt-Regular.ttf +0 -0
  589. package/lib/commonjs/assets/assets/fonts/Inter/Inter_18pt-SemiBold.ttf +0 -0
  590. package/lib/commonjs/assets/fonts/Inter/Inter_18pt-Black.ttf +0 -0
  591. package/lib/commonjs/assets/fonts/Inter/Inter_18pt-Bold.ttf +0 -0
  592. package/lib/commonjs/assets/fonts/Inter/Inter_18pt-ExtraBold.ttf +0 -0
  593. package/lib/commonjs/assets/fonts/Inter/Inter_18pt-Light.ttf +0 -0
  594. package/lib/commonjs/assets/fonts/Inter/Inter_18pt-Medium.ttf +0 -0
  595. package/lib/commonjs/assets/fonts/Inter/Inter_18pt-Regular.ttf +0 -0
  596. package/lib/commonjs/assets/fonts/Inter/Inter_18pt-SemiBold.ttf +0 -0
  597. package/lib/commonjs/ui/components/FontLoader.js +0 -35
  598. package/lib/commonjs/ui/components/FontLoader.js.map +0 -1
  599. package/lib/commonjs/ui/components/FontLoader.native.js +0 -88
  600. package/lib/commonjs/ui/components/FontLoader.native.js.map +0 -1
  601. package/lib/commonjs/ui/components/oxyAuthChooserStyles.js.map +0 -1
  602. package/lib/module/assets/assets/fonts/Inter/Inter_18pt-Black.ttf +0 -0
  603. package/lib/module/assets/assets/fonts/Inter/Inter_18pt-Bold.ttf +0 -0
  604. package/lib/module/assets/assets/fonts/Inter/Inter_18pt-ExtraBold.ttf +0 -0
  605. package/lib/module/assets/assets/fonts/Inter/Inter_18pt-Light.ttf +0 -0
  606. package/lib/module/assets/assets/fonts/Inter/Inter_18pt-Medium.ttf +0 -0
  607. package/lib/module/assets/assets/fonts/Inter/Inter_18pt-Regular.ttf +0 -0
  608. package/lib/module/assets/assets/fonts/Inter/Inter_18pt-SemiBold.ttf +0 -0
  609. package/lib/module/assets/fonts/Inter/Inter_18pt-Black.ttf +0 -0
  610. package/lib/module/assets/fonts/Inter/Inter_18pt-Bold.ttf +0 -0
  611. package/lib/module/assets/fonts/Inter/Inter_18pt-ExtraBold.ttf +0 -0
  612. package/lib/module/assets/fonts/Inter/Inter_18pt-Light.ttf +0 -0
  613. package/lib/module/assets/fonts/Inter/Inter_18pt-Medium.ttf +0 -0
  614. package/lib/module/assets/fonts/Inter/Inter_18pt-Regular.ttf +0 -0
  615. package/lib/module/assets/fonts/Inter/Inter_18pt-SemiBold.ttf +0 -0
  616. package/lib/module/ui/components/FontLoader.js +0 -29
  617. package/lib/module/ui/components/FontLoader.js.map +0 -1
  618. package/lib/module/ui/components/FontLoader.native.js +0 -83
  619. package/lib/module/ui/components/FontLoader.native.js.map +0 -1
  620. package/lib/module/ui/components/oxyAuthChooserStyles.js.map +0 -1
  621. package/lib/typescript/commonjs/ui/components/FontLoader.d.ts +0 -24
  622. package/lib/typescript/commonjs/ui/components/FontLoader.d.ts.map +0 -1
  623. package/lib/typescript/commonjs/ui/components/FontLoader.native.d.ts +0 -13
  624. package/lib/typescript/commonjs/ui/components/FontLoader.native.d.ts.map +0 -1
  625. package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts.map +0 -1
  626. package/lib/typescript/module/ui/components/FontLoader.d.ts +0 -24
  627. package/lib/typescript/module/ui/components/FontLoader.d.ts.map +0 -1
  628. package/lib/typescript/module/ui/components/FontLoader.native.d.ts +0 -13
  629. package/lib/typescript/module/ui/components/FontLoader.native.d.ts.map +0 -1
  630. package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts.map +0 -1
  631. package/src/assets/fonts/Inter/Inter_18pt-Black.ttf +0 -0
  632. package/src/assets/fonts/Inter/Inter_18pt-Bold.ttf +0 -0
  633. package/src/assets/fonts/Inter/Inter_18pt-ExtraBold.ttf +0 -0
  634. package/src/assets/fonts/Inter/Inter_18pt-Light.ttf +0 -0
  635. package/src/assets/fonts/Inter/Inter_18pt-Medium.ttf +0 -0
  636. package/src/assets/fonts/Inter/Inter_18pt-Regular.ttf +0 -0
  637. package/src/assets/fonts/Inter/Inter_18pt-SemiBold.ttf +0 -0
  638. package/src/ui/components/FontLoader.native.tsx +0 -88
  639. package/src/ui/components/FontLoader.tsx +0 -27
@@ -10,35 +10,22 @@
10
10
  * cross-origin passkey popup (b2) — same chooser, two hosts, two completion
11
11
  * strategies via the `onComplete` prop. Neither host duplicates view logic.
12
12
  *
13
- * Views (from `snapshot.view`):
14
- * - `accounts` the unified `SwitchableAccount[]` list. Tapping a row
15
- * switches through `controller.switchTo(accountId)`, the active row is
16
- * flagged, and a "+ Add account" row opens the sign-in entry.
17
- * - `add` / `signin` — the sign-in entry. On WEB this auto-starts "Sign in
18
- * with Oxy" (native shared-keychain silently, else the QR handoff) the
19
- * instant the view is entered the QR is the PRIMARY web surface, not a
20
- * button behind a click. On NATIVE it stays button-driven (unchanged):
21
- * primary "Sign in with Oxy", secondary "Scan a QR from another device".
22
- * Both platforms get a footer entry into `signup`.
23
- * - `signup` account creation. Commons is ALWAYS the priority path (owner
24
- * mandate) and leads everywhere it appears: native shows only "Create your
25
- * identity in Commons" (or "Get Commons" first, if not installed); web on
26
- * a first-party Oxy origin leads with the SAME "Get Commons" CTA, with
27
- * inline passkey creation (username + `registerWithPasskey`) offered
28
- * UNDERNEATH as the de-emphasized "don't want to install anything"
29
- * alternative — never co-equal, never a competing button. Anywhere else (a
30
- * non-Oxy web origin, before the b2 hub-relay ships) shows an honest "not
31
- * available here yet" message instead of a broken button.
32
- * - `qr` — the cross-device Commons handoff, and the PRIMARY web sign-in
33
- * surface. On a first-party Oxy origin this ALSO carries a "No Commons?"
34
- * passkey link — identity is ONE thing (Commons key or browser passkey,
35
- * same Oxy ID), so there is no separate "sign in with a passkey" button
36
- * anywhere in this file, but passkey is explicitly the LIGHTWEIGHT
37
- * ALTERNATIVE for someone who doesn't want to install Commons, never
38
- * co-equal: same small-text-link subordination, same framing, wherever it
39
- * appears. Native additionally branches on `commonsAvailability`: when
40
- * Commons isn't installed, this leads with a "Get Commons" CTA instead of
41
- * a same-device dead-end QR.
13
+ * This file owns WIRING only: the controller binding, the action handlers, and
14
+ * which view module renders. Every view lives in `./authChooser/`, one
15
+ * responsibility each:
16
+ *
17
+ * - `accounts` `AccountsMenuView` — the signed-in Oxy account menu.
18
+ * - `add` / `signin` `SignInEntryView` ONE primary action, "Continue with
19
+ * Oxy" (issue #691, Phase 5). On WEB this view is transient: the flow
20
+ * auto-starts the instant the view is reached, because the request surface
21
+ * (a QR on an unknown desktop, "Check Commons on your phone" where Oxy could
22
+ * deliver) IS the primary route there, never something behind a second tap.
23
+ * - `qr` `SignInRequestView` the ACTIVE REQUEST: the controller-bound
24
+ * wiring over the shared, presentational `OxySignInRequestSurface` (the same
25
+ * component the auth.oxy.so IdP mounts from its OAuth-bound request). It maps
26
+ * `snapshot.signIn` onto that surface's props; alternatives stay behind
27
+ * "Having trouble?" until the chosen route reports `routeFailed`.
28
+ * - `signup` `SignUpView` account creation, Commons-first.
42
29
  *
43
30
  * Per-account color re-theming uses Bloom's `APP_COLOR_PRESETS` + `BloomColorScope`
44
31
  * (same visual language auth.oxy.so uses). Base theming is `useTheme()` + a
@@ -47,49 +34,12 @@
47
34
  */
48
35
 
49
36
  import type React from 'react';
50
- import {
51
- Fragment,
52
- useCallback,
53
- useMemo,
54
- useRef,
55
- useState,
56
- useSyncExternalStore,
57
- } from 'react';
58
- import {
59
- Linking,
60
- Platform,
61
- Pressable,
62
- TextInput,
63
- View,
64
- type StyleProp,
65
- type ViewStyle,
66
- } from 'react-native';
67
- import Animated, {
68
- Extrapolation,
69
- interpolate,
70
- useAnimatedStyle,
71
- useSharedValue,
72
- withTiming,
73
- } from 'react-native-reanimated';
74
- import { MaterialCommunityIcons } from '@expo/vector-icons';
75
- import QRCode from 'react-native-qrcode-svg';
76
- import { Avatar } from '@oxyhq/bloom/avatar';
77
- import { AvatarGroup, type AvatarGroupItem } from '@oxyhq/bloom/avatar-group';
78
- import { Button } from '@oxyhq/bloom/button';
79
- import { PressableScale } from '@oxyhq/bloom/pressable-scale';
80
- import { CompositionBar, type CompositionCategory } from '@oxyhq/bloom/composition-bar';
81
- import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
37
+ import { useCallback, useMemo, useState, useSyncExternalStore } from 'react';
38
+ import { Linking, Platform } from 'react-native';
82
39
  import { toast } from '@oxyhq/bloom';
83
- import { Text } from '@oxyhq/bloom/typography';
84
- import {
85
- useTheme,
86
- BloomColorScope,
87
- APP_COLOR_NAMES,
88
- APP_COLOR_PRESETS,
89
- type AppColorName,
90
- } from '@oxyhq/bloom/theme';
91
- import type { AccountDialogSnapshot, OxyServices, SwitchableAccount } from '@oxyhq/core';
92
- import { getNormalizedUserHandle, isOxyRpOrigin } from '@oxyhq/core';
40
+ import { useTheme } from '@oxyhq/bloom/theme';
41
+ import type { AccountDialogSnapshot } from '@oxyhq/core';
42
+ import { isOxyRpOrigin } from '@oxyhq/core';
93
43
  import { useQueryClient } from '@tanstack/react-query';
94
44
  import { useOxy } from '../context/OxyContext';
95
45
  import { useI18n } from '../hooks/useI18n';
@@ -97,15 +47,18 @@ import { getAccountDialogConsumerHooks } from '../navigation/accountDialogManage
97
47
  import { isWebBrowser } from '../utils/isWebBrowser';
98
48
  import { getCommonsAcquisitionUrl } from '../utils/commonsStoreLinks';
99
49
  import { useAccountStorageUsage } from '../hooks/queries/useServicesQueries';
100
- import { authChooserStyles as styles } from './oxyAuthChooserStyles';
101
- import AvatarCameraBadge from './AvatarCameraBadge';
50
+ import AccountsMenuView from './authChooser/AccountsMenuView';
51
+ import SignInEntryView from './authChooser/SignInEntryView';
52
+ import SignInRequestView from './authChooser/SignInRequestView';
53
+ import SignUpView from './authChooser/SignUpView';
54
+ import type {
55
+ AccountStorageModel,
56
+ AccountsMenuActions,
57
+ OxyAuthChooserHandlers,
58
+ PasskeyMode,
59
+ SignInAlternatives,
60
+ } from './authChooser/types';
102
61
 
103
- /** Diameter of a row avatar (the sign-in view's account rows). */
104
- const ROW_AVATAR_SIZE = 40;
105
- /** High-contrast QR colors — intentionally fixed (NOT themed) for scan reliability. */
106
- const QR_PLATE_BG = '#FFFFFF';
107
- const QR_FOREGROUND = '#000000';
108
- const QR_SIZE = 196;
109
62
  /** Commons' own identity-creation deep link (mirrors the `approve`/`attest`/`card` intents). */
110
63
  const COMMONS_CREATE_IDENTITY_URL = 'oxycommons://create-identity';
111
64
  /**
@@ -121,41 +74,6 @@ export interface OxyAuthChooserProps {
121
74
  onComplete?: () => void;
122
75
  }
123
76
 
124
- /**
125
- * Resolve an account's stored color (a named Bloom preset, e.g. `'purple'`) to
126
- * a concrete brand hex for the row accent. Falls back to the theme primary when
127
- * the account has no color or the value is not a recognized preset, so the accent
128
- * renders in EVERY consumer regardless of NativeWind availability.
129
- */
130
- function resolveAccentHex(color: string | null, fallback: string): string {
131
- const preset = toPreset(color);
132
- return preset ? APP_COLOR_PRESETS[preset].hex : fallback;
133
- }
134
-
135
- /** Narrow a stored color string to a known `AppColorName`, or `undefined`. */
136
- function toPreset(color: string | null): AppColorName | undefined {
137
- if (!color) return undefined;
138
- return (APP_COLOR_NAMES as readonly string[]).includes(color)
139
- ? (color as AppColorName)
140
- : undefined;
141
- }
142
-
143
- interface OxyAuthChooserHandlers {
144
- onSwitch: (accountId: string) => void;
145
- onAdd: () => void;
146
- onManage: () => void;
147
- /**
148
- * Change the current account's photo — opens the avatar-change flow. Because
149
- * the account menu lives in the AccountDialog surface, this MORPHS that surface
150
- * into `ChangeAvatar` (via `openAvatarPicker` → `openWithinOrPresent`), the same
151
- * flow ManageAccount's avatar uses; it never stacks a new dialog.
152
- */
153
- onEditAvatar: () => void;
154
- }
155
-
156
- type Theme = ReturnType<typeof useTheme>;
157
- type Translate = ReturnType<typeof useI18n>['t'];
158
-
159
77
  /**
160
78
  * The account switcher + sign-in/sign-up chooser. Mounted by `OxyAccountDialogScreen`
161
79
  * (wrapped in Bloom's `<Dialog>`) today; mountable bare by any future host that
@@ -185,11 +103,10 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
185
103
  // back via `AccountDialogController.startPasskeyHubSignIn` ('hub'). Native
186
104
  // has neither: Commons owns identity there ('none'). `isOxyRpOrigin()` reads
187
105
  // `location` once and is stable for the component's lifetime.
188
- const passkeyMode = useMemo<'direct' | 'hub' | 'none'>(() => {
106
+ const passkeyMode = useMemo<PasskeyMode>(() => {
189
107
  if (!isWebBrowser()) return 'none';
190
108
  return isOxyRpOrigin() ? 'direct' : 'hub';
191
109
  }, []);
192
- const passkeyAvailable = passkeyMode !== 'none';
193
110
 
194
111
  const [signInPasskeyPending, setSignInPasskeyPending] = useState(false);
195
112
  const handleSignInWithPasskey = useCallback(async () => {
@@ -205,7 +122,7 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
205
122
  toast.error(
206
123
  error instanceof Error && error.message
207
124
  ? error.message
208
- : t('accountSwitcher.toasts.passkeySignInFailed') || 'Passkey sign-in failed.',
125
+ : t('accountSwitcher.toasts.passkeySignInFailed'),
209
126
  );
210
127
  } finally {
211
128
  setSignInPasskeyPending(false);
@@ -224,7 +141,7 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
224
141
  toast.error(
225
142
  error instanceof Error && error.message
226
143
  ? error.message
227
- : t('signup.toasts.passkeyCreateFailed') || 'Account creation failed.',
144
+ : t('signup.toasts.passkeyCreateFailed'),
228
145
  );
229
146
  } finally {
230
147
  setCreatePasskeyPending(false);
@@ -234,13 +151,14 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
234
151
  );
235
152
 
236
153
  // Web: auto-start "Sign in with Oxy" when the sign-in entry becomes the shown
237
- // view — the QR handoff is the PRIMARY web surface, not a button behind a tap.
154
+ // view — the request surface is the PRIMARY web route, not something behind a
155
+ // second tap (the user's ONE action was the sign-in button that opened this).
238
156
  // `signInWithOxy()` tries the shared keychain first (silently, native-only)
239
- // then falls to the QR handoff, which is what actually renders. Driven from the
240
- // EVENTS that reach that view — the initial `subscribe` pass below (an
157
+ // then falls to the device flow, whose route the controller picks. Driven from
158
+ // the EVENTS that reach that view — the initial `subscribe` pass below (an
241
159
  // open-to-sign-in) and the add / back-to-sign-in handlers — never a watcher
242
- // effect. Guarded so it never restarts a live flow (phase must be idle) and is a
243
- // no-op on native (button-driven). Reads the live snapshot at call time (an
160
+ // effect. Guarded so it never restarts a live flow (phase must be idle) and is
161
+ // a no-op on native (button-driven). Reads the live snapshot at call time (an
244
162
  // event callback, not render), so it is stable across renders.
245
163
  const autoStartSignIn = useCallback(() => {
246
164
  if (!controller || !isWebBrowser()) return;
@@ -258,8 +176,8 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
258
176
  // callbacks, not render/effect — so neither is a React effect hook:
259
177
  // 1. Sign-in device-flow failures (poll / socket / popup-cancel land on
260
178
  // `signIn` asynchronously) are toasted at the notification site, deduped
261
- // per subscription — NEVER an inline banner in the QR view (owner mandate,
262
- // same contract as account-switch).
179
+ // per subscription — NEVER an inline banner in the request view (owner
180
+ // mandate, same contract as account-switch).
263
181
  // 2. On subscribe (mount / re-subscribe — a passive effect, the SAME timing
264
182
  // the removed effects had) the web sign-in flow auto-starts if the opening
265
183
  // view is the sign-in entry.
@@ -312,10 +230,7 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
312
230
  // re-fetches — the same side effects the context's own
313
231
  // `switchToAccount` performs.
314
232
  if (controller.getSnapshot().error) {
315
- toast.error(
316
- t('accountSwitcher.toasts.switchFailed') ||
317
- 'There was a problem switching accounts. Please try again.',
318
- );
233
+ toast.error(t('accountSwitcher.toasts.switchFailed'));
319
234
  return;
320
235
  }
321
236
  void refreshAccounts();
@@ -364,9 +279,34 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
364
279
  [handleSwitch, handleAdd, handleManage, openAvatarPicker],
365
280
  );
366
281
 
282
+ // Everything that is NOT the surface's one primary action. Wired once here;
283
+ // each view picks the subset that is a genuine alternative to ITS primary
284
+ // surface and hides them behind "Having trouble?" (issue #691).
285
+ const alternatives = useMemo<SignInAlternatives>(
286
+ () => ({
287
+ passkeyAvailable: passkeyMode !== 'none',
288
+ // The hub-popup flow reports progress through `snapshot.signIn` (already
289
+ // rendered by the request view) — only the DIRECT ceremony uses this
290
+ // component-local pending flag. A ceremony FAILURE is toasted by
291
+ // `handleSignInWithPasskey`, never rendered inline.
292
+ passkeyPending: passkeyMode === 'direct' ? signInPasskeyPending : false,
293
+ onSignInWithPasskey: () => {
294
+ if (passkeyMode === 'direct') {
295
+ void handleSignInWithPasskey();
296
+ return;
297
+ }
298
+ void controller?.startPasskeyHubSignIn();
299
+ },
300
+ onShowQr: () => void controller?.showQr(),
301
+ onGetCommons: () => void Linking.openURL(getCommonsAcquisitionUrl(Platform.OS)),
302
+ onCreateAccount: () => controller?.startSignup(),
303
+ }),
304
+ [passkeyMode, signInPasskeyPending, handleSignInWithPasskey, controller],
305
+ );
306
+
367
307
  // Real storage usage for the account menu's "Oxy storage" block. Disabled
368
308
  // (no fetch) until a private-API session exists, so it is inert on the
369
- // sign-in/QR/sign-up views; when present the block shows live used/total.
309
+ // sign-in/request/sign-up views; when present the block shows live used/total.
370
310
  const storageQuery = useAccountStorageUsage();
371
311
  const storage = useMemo<AccountStorageModel | null>(
372
312
  () =>
@@ -413,7 +353,7 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
413
353
 
414
354
  if (view === 'accounts') {
415
355
  return (
416
- <AccountsView
356
+ <AccountsMenuView
417
357
  snapshot={snapshot}
418
358
  theme={theme}
419
359
  t={t}
@@ -426,23 +366,11 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
426
366
 
427
367
  if (view === 'qr') {
428
368
  return (
429
- <QrView
369
+ <SignInRequestView
430
370
  snapshot={snapshot}
431
- theme={theme}
432
371
  t={t}
433
372
  onRetry={() => void controller.showQr()}
434
- passkeyAvailable={passkeyAvailable}
435
- onSignInWithPasskey={
436
- passkeyMode === 'direct'
437
- ? () => void handleSignInWithPasskey()
438
- : () => void controller.startPasskeyHubSignIn()
439
- }
440
- // The hub-popup flow's pending state is `snapshot.signIn` (already
441
- // rendered elsewhere in this view) — only the DIRECT ceremony uses this
442
- // component-local pending flag. A ceremony FAILURE is surfaced as a
443
- // toast by `handleSignInWithPasskey`, never inline.
444
- passkeyPending={passkeyMode === 'direct' ? signInPasskeyPending : false}
445
- onCreateAccount={() => controller.startSignup()}
373
+ alternatives={alternatives}
446
374
  />
447
375
  );
448
376
  }
@@ -455,9 +383,11 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
455
383
  t={t}
456
384
  oxyServices={oxyServices}
457
385
  passkeyMode={passkeyMode}
458
- onCreateWithPasskey={handleCreateWithPasskey}
386
+ onCreateWithPasskey={(username) => void handleCreateWithPasskey(username)}
459
387
  createPending={createPasskeyPending}
460
388
  onOpenHub={() => void controller.startPasskeyHubSignIn()}
389
+ onCreateIdentityInCommons={() => void Linking.openURL(COMMONS_CREATE_IDENTITY_URL)}
390
+ onGetCommons={alternatives.onGetCommons}
461
391
  onBackToSignIn={() => {
462
392
  controller.setView('signin');
463
393
  autoStartSignIn();
@@ -467,1097 +397,17 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
467
397
  }
468
398
 
469
399
  return (
470
- <SignInView
400
+ <SignInEntryView
471
401
  snapshot={snapshot}
472
402
  theme={theme}
473
403
  t={t}
474
404
  handlers={handlers}
475
- onSignInWithOxy={() => void controller.signInWithOxy()}
476
- onScanQr={() => void controller.showQr()}
477
- onCreateAccount={() => controller.startSignup()}
478
- />
479
- );
480
- };
481
-
482
- // ---------------------------------------------------------------------------
483
- // Accounts view — the signed-in Oxy account MENU (NativeWind)
484
- // ---------------------------------------------------------------------------
485
-
486
- /** Used/total storage bytes for the "Oxy storage" block, or `null` when unknown. */
487
- interface AccountStorageModel {
488
- usedBytes: number;
489
- limitBytes: number;
490
- }
491
-
492
- /** The account-menu row actions the container wires (deep-links / sheets / sign-out). */
493
- interface AccountsMenuActions {
494
- onOpenSettings: () => void;
495
- onOpenData: () => void;
496
- onManageStorage: () => void;
497
- onUpgradeStorage: () => void;
498
- onHelp: () => void;
499
- onPrivacy: () => void;
500
- onTerms: () => void;
501
- onSignOut: () => void;
502
- }
503
-
504
- interface AccountsViewProps {
505
- snapshot: AccountDialogSnapshot;
506
- theme: Theme;
507
- t: Translate;
508
- handlers: OxyAuthChooserHandlers;
509
- storage: AccountStorageModel | null;
510
- menu: AccountsMenuActions;
511
- }
512
-
513
- /**
514
- * Leading glyph for the rows that live in a Bloom grouped section (the MENU
515
- * block) and for the storage card's cloud, which lines its title up with them.
516
- * It is Bloom's OWN icon-slot size: `SettingsListItem` reserves a fixed 20px
517
- * leading column and Bloom is consumed exactly as it ships, so a menu glyph
518
- * larger than this would overhang into the row's title.
519
- */
520
- const ROW_ICON_SIZE = 20;
521
- /**
522
- * The switch card's two corner states. Collapsed it is one row and reads as a
523
- * PILL; opened it is a card holding rows, on the same 16px corner the Bloom
524
- * grouped section below it uses. Interpolated across the reveal, never snapped.
525
- */
526
- const SWITCH_CARD_PILL_RADIUS = 999;
527
- const SWITCH_CARD_RADIUS = 16;
528
- /**
529
- * The fraction of the reveal over which the corner resolves. The corner is a
530
- * FASTER gesture than the reveal — it has to be finished before the rows read as
531
- * rows, or the card still looks like a pill while a list falls out of it — so it
532
- * is clamped to the reveal's opening fraction instead of tracking it end to end.
533
- * Measured in a browser against the 240ms reveal: the corner reaches its card
534
- * value ~120ms in, with the list only ~20% revealed, and (mirrored) the pill is
535
- * back ~250ms into the close, with the list already down to ~0.
536
- */
537
- const SWITCH_CARD_RADIUS_SETTLE = 0.2;
538
- /** Diameter of an account row's avatar in the switch list (own markup). */
539
- const SWITCH_AVATAR_SIZE = 36;
540
- /** Glyph inside a bordered affordance badge, sized to the avatar it stands in for. */
541
- const BADGE_GLYPH_SIZE = 19;
542
- /** The hero block's large current-account avatar. */
543
- const HERO_AVATAR_SIZE = 72;
544
-
545
- /**
546
- * The hero's address line, shown under the "Hi, <name>!" greeting: the account's
547
- * canonical `@oxy.so` email when it has one, else its normalized `@handle`. Never
548
- * synthesizes a `username@oxy.so` address (the identity contract forbids it) — a
549
- * non-Oxy or missing email falls back to `getNormalizedUserHandle`.
550
- */
551
- function heroAddressLine(account: SwitchableAccount): string | null {
552
- if (account.email?.toLowerCase().endsWith('@oxy.so')) {
553
- return account.email;
554
- }
555
- const handle = getNormalizedUserHandle(account.user);
556
- return handle ? `@${handle}` : null;
557
- }
558
- /** Avatars shown in the switch row's facepile before it collapses into `+N`. */
559
- const FACEPILE_MAX = 2;
560
- /** Facepile avatar diameter — one clear step down from a switch-list avatar. */
561
- const FACEPILE_AVATAR_SIZE = 32;
562
- /**
563
- * Facepile overlap. Well under Bloom's `size / 3` default: the stack draws the
564
- * FIRST item on top, so a deep overlap would bury the trailing `+N` chip's own
565
- * label under the avatar before it.
566
- */
567
- const FACEPILE_OVERLAP = 4;
568
-
569
-
570
- /**
571
- * `bytes` → `"11.6 GB"`. Whole plan sizes read as whole numbers (`"17 GB"`, not
572
- * `"17.0 GB"`), and anything ≥ 100 GB drops the decimal entirely.
573
- */
574
- function formatStorageGb(bytes: number): string {
575
- const gb = bytes / 1024 ** 3;
576
- if (gb >= 100 || Number.isInteger(gb)) return `${Math.round(gb)} GB`;
577
- return `${gb.toFixed(1)} GB`;
578
- }
579
-
580
- type HoverPressableProps = Omit<React.ComponentProps<typeof Pressable>, 'className'> & {
581
- baseClassName: string;
582
- hoverClassName: string;
583
- };
584
-
585
- /**
586
- * A `Pressable` that appends a hover-tint NativeWind token while pointer-hovered.
587
- * The Metro web pipeline here does NOT emit NativeWind `hover:` variants, so hover
588
- * is driven by RN's cross-platform `onHoverIn`/`onHoverOut` (they fire only on web
589
- * via react-native-web; a no-op on native) toggling a plain background token —
590
- * the tint stays a NativeWind class, only the trigger is JS.
591
- */
592
- const HoverPressable: React.FC<HoverPressableProps> = ({
593
- baseClassName,
594
- hoverClassName,
595
- ...rest
596
- }) => {
597
- const [hovered, setHovered] = useState(false);
598
- return (
599
- <Pressable
600
- {...rest}
601
- className={hovered ? `${baseClassName} ${hoverClassName}` : baseClassName}
602
- onHoverIn={() => setHovered(true)}
603
- onHoverOut={() => setHovered(false)}
405
+ onContinueWithOxy={() => void controller.signInWithOxy()}
406
+ alternatives={alternatives}
604
407
  />
605
408
  );
606
409
  };
607
410
 
608
- /**
609
- * The signed-in Oxy account MENU — a Google-account-menu-style full menu built
610
- * entirely with NativeWind `className` (the dynamic per-account accent hex is
611
- * the one inline style NativeWind can't express). Structure mirrors the
612
- * approved demo:
613
- * - ACCOUNT on its own distinct panel surface: a COMPACT current-account row
614
- * (avatar + name + email + expand chevron) that toggles the switch list, a
615
- * "Manage your Oxy account" pill, and — when expanded — the other switchable
616
- * accounts + "Add another account" + "Manage accounts on this device".
617
- * - OXY STORAGE: cloud + used/total + a progress bar + Upgrade / Manage chips.
618
- * - MENU rows: Your data in Oxy · Oxy settings · Help & feedback · Sign out —
619
- * Bloom's grouped section (`SettingsListGroup`/`SettingsListItem`), the same
620
- * component every other SDK settings surface uses, not a local row copy.
621
- * - FOOTER: Privacy Policy · Terms of Service.
622
- *
623
- * All three blocks share ONE rhythm taken from that grouped section: a 12px
624
- * content inset, a 12px gap after the leading element, 16px between blocks, and
625
- * a 16px trailing chevron column.
626
- *
627
- * Collapse state is a plain `useState` toggled in the current row's press
628
- * handler — no effect hook, no derived-from-props sync. With only ONE account
629
- * (nothing to switch to) the chevron is hidden and the list renders inline so
630
- * "Add another account" stays reachable without a pointless toggle.
631
- */
632
- const AccountsView: React.FC<AccountsViewProps> = ({
633
- snapshot,
634
- theme,
635
- t,
636
- handlers,
637
- storage,
638
- menu,
639
- }) => {
640
- const [expanded, setExpanded] = useState(false);
641
- // Measured natural height of the switch list, so the reveal animates to an
642
- // exact height (and the content below reflows down smoothly) instead of a
643
- // guessed max. The measuring wrapper is style-based, NOT className'd — on
644
- // RN-Web `onLayout` never fires for className'd Views (see AGENTS.md).
645
- const [listContentHeight, setListContentHeight] = useState(0);
646
- // 0 = collapsed, 1 = expanded. Set imperatively in the toggle handler (no
647
- // effect hook). On RN-Web there is no worklets plugin, so every shared value a
648
- // mapper reads MUST be in its deps array or it freezes on the first frame
649
- // (AGENTS.md "Reanimated (web)").
650
- const listProgress = useSharedValue(0);
651
- const listStyle = useAnimatedStyle(
652
- () => ({ height: listProgress.value * listContentHeight, opacity: listProgress.value }),
653
- [listProgress, listContentHeight],
654
- );
655
- const chevronStyle = useAnimatedStyle(
656
- () => ({ transform: [{ rotate: `${listProgress.value * 180}deg` }] }),
657
- [listProgress],
658
- );
659
- // Collapsed, the switch card is a single row and reads as a PILL; opened, it
660
- // becomes a card holding rows and takes the grouped-section corner. The corner
661
- // is driven off the SAME `listProgress` as the reveal — but clamped to its
662
- // opening fraction, so it resolves early instead of trailing the rows: the
663
- // card already reads as a card by the time they are visible. Collapsing is the
664
- // mirror image, the pill returning over the closing tail.
665
- const switchCardStyle = useAnimatedStyle(
666
- () => ({
667
- borderRadius: interpolate(
668
- listProgress.value,
669
- [0, SWITCH_CARD_RADIUS_SETTLE],
670
- [SWITCH_CARD_PILL_RADIUS, SWITCH_CARD_RADIUS],
671
- Extrapolation.CLAMP,
672
- ),
673
- }),
674
- [listProgress],
675
- );
676
- // `CompositionBar` ships as an interactive breakdown: a selected segment
677
- // replaces its hint line with that segment's readout. Tapping the selected one
678
- // again clears it.
679
- const [storageSegment, setStorageSegment] = useState<string | null>(null);
680
- const toggleStorageSegment = useCallback(
681
- (key: string) => setStorageSegment((previous) => (previous === key ? null : key)),
682
- [],
683
- );
684
- const toggleExpanded = useCallback(() => {
685
- const next = !expanded;
686
- setExpanded(next);
687
- listProgress.value = withTiming(next ? 1 : 0, { duration: 240 });
688
- }, [expanded, listProgress]);
689
-
690
- if (snapshot.loading && snapshot.accounts.length === 0) {
691
- return (
692
- <View className="items-center justify-center gap-space-12 py-space-24">
693
- <MaterialCommunityIcons name="loading" size={24} color={theme.colors.textSecondary} />
694
- <Text className="text-body text-text-secondary text-center">
695
- {t('accountSwitcher.loading')}
696
- </Text>
697
- </View>
698
- );
699
- }
700
-
701
- const switchingDisabled = snapshot.switchingAccountId !== null;
702
- const current = snapshot.accounts.find((account) => account.isCurrent) ?? snapshot.accounts[0];
703
- const others = current
704
- ? snapshot.accounts.filter((account) => account.accountId !== current.accountId)
705
- : snapshot.accounts;
706
- const currentAccent = current
707
- ? resolveAccentHex(current.color, theme.colors.primary)
708
- : theme.colors.primary;
709
- // The hero's address line under the greeting: the account's canonical @oxy.so
710
- // email when it has one, else its normalized `@handle` (never a synthesized
711
- // `username@oxy.so`, per the identity contract — `getNormalizedUserHandle`).
712
- const currentAddress = current ? heroAddressLine(current) : null;
713
- // The switch list repeats the CURRENT account (first, ringed) — unlike the old
714
- // compact header it is not represented anywhere else once the hero moved out
715
- // of the card, and the list is where you switch back to it.
716
- const switchableAccounts = current ? [current, ...others] : others;
717
- const facepile: AvatarGroupItem[] = switchableAccounts.map((account) => ({
718
- id: account.accountId,
719
- uri: account.avatarUrl ?? undefined,
720
- displayName: account.displayName,
721
- }));
722
-
723
- // Used vs free is a two-part COMPOSITION (the parts always fill the bar), not
724
- // a progress value — exactly what Bloom's `CompositionBar` models. Both colors
725
- // are theme tokens, so the bar is correct in light and dark.
726
- const storageCategories: CompositionCategory[] = storage
727
- ? [
728
- {
729
- key: 'used',
730
- name: t('accountMenu.storage.used'),
731
- amount: storage.usedBytes,
732
- color: theme.colors.primary,
733
- },
734
- {
735
- key: 'free',
736
- name: t('accountMenu.storage.free'),
737
- amount: Math.max(0, storage.limitBytes - storage.usedBytes),
738
- color: theme.colors.contrast50,
739
- },
740
- ]
741
- : [];
742
- const usageLabel = storage
743
- ? t('accountMenu.storage.usage', {
744
- used: formatStorageGb(storage.usedBytes),
745
- total: formatStorageGb(storage.limitBytes),
746
- })
747
- : t('accountMenu.storage.unavailable');
748
-
749
- // The switch list body, revealed under the "Switch account" row. Own markup,
750
- // not a Bloom grouped section: this is not a list of settings rows and the
751
- // component is not a card container. It mirrors the section's rhythm by hand —
752
- // 12px content inset, 12px after the avatar, a hairline between rows — and
753
- // draws those hairlines INSIDE the animated clip, so a collapsed list never
754
- // strands one against the header row.
755
- const listItems = (
756
- <>
757
- {switchableAccounts.map((account, index) => {
758
- const accent = resolveAccentHex(account.color, theme.colors.primary);
759
- const isSwitching = snapshot.switchingAccountId === account.accountId;
760
- return (
761
- <Fragment key={account.accountId}>
762
- {index > 0 ? <View className="h-px bg-border opacity-30 ml-space-12" /> : null}
763
- <HoverPressable
764
- baseClassName={`flex-row items-center gap-space-12 px-space-12 py-[10px]${
765
- switchingDisabled ? ' opacity-60' : ''
766
- }`}
767
- hoverClassName="bg-fill-secondary"
768
- onPress={() => handlers.onSwitch(account.accountId)}
769
- disabled={switchingDisabled}
770
- accessibilityRole="button"
771
- accessibilityLabel={account.displayName}
772
- >
773
- <View>
774
- <Avatar
775
- source={account.avatarUrl ?? undefined}
776
- variant="thumb"
777
- name={account.displayName}
778
- size={SWITCH_AVATAR_SIZE}
779
- />
780
- {/* The accent ring is an OVERLAY: it costs the row no width, so
781
- every avatar in the list starts on the same content line. */}
782
- {account.isCurrent ? (
783
- <View
784
- style={[styles.currentAvatarRing, { borderColor: accent }]}
785
- pointerEvents="none"
786
- />
787
- ) : null}
788
- </View>
789
- <View className="flex-1 min-w-0">
790
- <Text className="text-body font-semibold text-text" numberOfLines={1}>
791
- {account.displayName}
792
- </Text>
793
- {account.email ? (
794
- <Text className="text-caption text-text-secondary" numberOfLines={1}>
795
- {account.email}
796
- </Text>
797
- ) : null}
798
- </View>
799
- {isSwitching ? (
800
- <MaterialCommunityIcons name="loading" size={20} color={accent} />
801
- ) : null}
802
- </HoverPressable>
803
- </Fragment>
804
- );
805
- })}
806
-
807
- <View className="h-px bg-border opacity-30 ml-space-12" />
808
- <AccountAffordanceRow
809
- icon="plus"
810
- label={t('accountMenu.addAnother')}
811
- onPress={handlers.onAdd}
812
- disabled={switchingDisabled}
813
- theme={theme}
814
- />
815
- <View className="h-px bg-border opacity-30 ml-space-12" />
816
- <AccountAffordanceRow
817
- icon="account-multiple-outline"
818
- label={t('accountSwitcher.manageOnDevice')}
819
- onPress={handlers.onManage}
820
- disabled={switchingDisabled}
821
- theme={theme}
822
- />
823
- </>
824
- );
825
-
826
- const manageLabel = t('accountMenu.manage');
827
- const switchLabel = t('accountMenu.switchAccount');
828
-
829
- return (
830
- <View>
831
- {/* HERO — chrome-free and centred, in the reference's reading order:
832
- NOTHING above the avatar (the nav bar's Oxy wordmark stands alone), the
833
- large pressable avatar (with a camera badge to change the photo), then
834
- the greeting, then the account address under it, then the manage action.
835
- The nav bar above stays BRANDED (see `OxyAccountDialogScreen`). */}
836
- <View style={styles.hero}>
837
- {current ? (
838
- <>
839
- <PressableScale
840
- onPress={handlers.onEditAvatar}
841
- accessibilityRole="button"
842
- accessibilityLabel={t('editProfile.changeAvatar')}
843
- style={styles.heroAvatarPressable}
844
- >
845
- <Avatar
846
- source={current.avatarUrl ?? undefined}
847
- name={current.displayName}
848
- size={HERO_AVATAR_SIZE}
849
- />
850
- <View
851
- style={[styles.heroAvatarRing, { borderColor: currentAccent }]}
852
- pointerEvents="none"
853
- />
854
- <AvatarCameraBadge />
855
- </PressableScale>
856
- <View style={styles.heroNameBlock}>
857
- <Text
858
- style={[styles.heroGreeting, { color: theme.colors.text }]}
859
- numberOfLines={2}
860
- >
861
- {t('accountMenu.greeting', { name: current.displayName })}
862
- </Text>
863
- {currentAddress ? (
864
- <Text
865
- style={[styles.heroAddress, { color: theme.colors.textSecondary }]}
866
- numberOfLines={1}
867
- >
868
- {currentAddress}
869
- </Text>
870
- ) : null}
871
- </View>
872
- </>
873
- ) : null}
874
- {/* Bloom's own compact outlined pill — `secondary` is the outlined
875
- variant, `small` the compact height; it hugs its label instead of
876
- spanning the surface. */}
877
- <Button
878
- variant="secondary"
879
- size="small"
880
- onPress={handlers.onManage}
881
- accessibilityLabel={manageLabel}
882
- >
883
- {manageLabel}
884
- </Button>
885
- </View>
886
-
887
- {/* SWITCH ACCOUNT — own NativeWind card, NOT a Bloom grouped section: it
888
- is a disclosure header over an animated list, not a list of settings
889
- rows, and the grouped section is not a bare card container. It borrows
890
- the section's LOOK by hand — the same `card` surface, 12px content inset
891
- and 16px gap to the next block — and its corner animates from a pill
892
- (collapsed, a single row) to that section's 16px card corner (opened,
893
- a card of rows) on the same `listProgress` the reveal runs on. */}
894
- <Animated.View className="bg-fill overflow-hidden mb-space-16" style={switchCardStyle}>
895
- <HoverPressable
896
- baseClassName={`flex-row items-center gap-space-12 px-space-12 py-[10px] min-h-[44px]${
897
- switchingDisabled ? ' opacity-60' : ''
898
- }`}
899
- hoverClassName="bg-fill-secondary"
900
- onPress={toggleExpanded}
901
- disabled={switchingDisabled}
902
- accessibilityRole="button"
903
- // The ARIA prop, not `accessibilityState`: react-native-web 0.21
904
- // forwards only this one, and RN maps it to
905
- // `accessibilityState.expanded` natively — so the disclosure state
906
- // reaches assistive tech on BOTH platforms.
907
- aria-expanded={expanded}
908
- accessibilityLabel={switchLabel}
909
- >
910
- <Text className="flex-1 text-body text-text" numberOfLines={1}>
911
- {switchLabel}
912
- </Text>
913
- {/* The facepile previews who you can switch to; once the list is open
914
- it would just restate the rows below it. */}
915
- {expanded ? null : (
916
- <AvatarGroup
917
- items={facepile}
918
- layout="stack"
919
- size={FACEPILE_AVATAR_SIZE}
920
- max={FACEPILE_MAX}
921
- overlap={FACEPILE_OVERLAP}
922
- variant="thumb"
923
- showInitials
924
- ringColor={theme.colors.card}
925
- />
926
- )}
927
- <View style={[styles.chevronCircle, { backgroundColor: theme.colors.contrast50 }]}>
928
- <Animated.View style={chevronStyle}>
929
- <MaterialCommunityIcons name="chevron-down" size={20} color={theme.colors.text} />
930
- </Animated.View>
931
- </View>
932
- </HoverPressable>
933
-
934
- {/* Animated reveal: an overflow-clipped container whose height + opacity
935
- are driven by `listProgress`; the inner style-based wrapper measures
936
- the natural content height via `onLayout`. */}
937
- <Animated.View
938
- style={[styles.collapse, listStyle]}
939
- pointerEvents={expanded ? 'auto' : 'none'}
940
- >
941
- <View
942
- style={styles.collapseMeasure}
943
- onLayout={(event) => setListContentHeight(event.nativeEvent.layout.height)}
944
- >
945
- <View>{listItems}</View>
946
- </View>
947
- </Animated.View>
948
- </Animated.View>
949
-
950
- {/* OXY STORAGE — own NativeWind card for the same reason: a title, a meter
951
- and two chips are not settings rows. Its cloud sits in the same 20px
952
- column Bloom's own rows use, so the title below lines up with the menu
953
- titles. `CompositionBar` is consumed exactly as it ships — an
954
- interactive breakdown at its own thickness, its hint line carrying the
955
- used/total copy and a tapped segment revealing that segment's share. */}
956
- <View className="bg-fill rounded-[16px] overflow-hidden mb-space-16 px-space-12 py-[10px] gap-space-12">
957
- <View className="flex-row items-center gap-space-12 min-h-[24px]">
958
- <View className="w-[20px] items-center">
959
- <MaterialCommunityIcons
960
- name="cloud-outline"
961
- size={ROW_ICON_SIZE}
962
- color={theme.colors.textSecondary}
963
- />
964
- </View>
965
- <Text className="flex-1 text-body font-semibold text-text" numberOfLines={1}>
966
- {t('accountMenu.storage.title')}
967
- </Text>
968
- </View>
969
- <CompositionBar
970
- categories={storageCategories}
971
- selectedKey={storageSegment}
972
- onSelect={toggleStorageSegment}
973
- hintLabel={usageLabel}
974
- formatReadout={(bytes, percent) => `${formatStorageGb(bytes)} · ${percent}%`}
975
- />
976
- <View className="flex-row gap-space-8">
977
- <StorageChip label={t('accountMenu.storage.upgrade')} onPress={menu.onUpgradeStorage} />
978
- <StorageChip label={t('accountMenu.storage.manage')} onPress={menu.onManageStorage} />
979
- </View>
980
- </View>
981
-
982
- {/* MENU — the same stock grouped section. */}
983
- <SettingsListGroup>
984
- <SettingsListItem
985
- icon={<MenuIcon name="tray-arrow-down" theme={theme} />}
986
- title={t('accountMenu.data')}
987
- onPress={menu.onOpenData}
988
- />
989
- <SettingsListItem
990
- icon={<MenuIcon name="cog-outline" theme={theme} />}
991
- title={t('accountMenu.settings')}
992
- onPress={menu.onOpenSettings}
993
- />
994
- <SettingsListItem
995
- icon={<MenuIcon name="help-circle-outline" theme={theme} />}
996
- title={t('accountMenu.help')}
997
- onPress={menu.onHelp}
998
- />
999
- <SettingsListItem
1000
- icon={<MenuIcon name="logout" theme={theme} />}
1001
- title={t('accountMenu.signOut')}
1002
- onPress={menu.onSignOut}
1003
- showChevron={false}
1004
- />
1005
- </SettingsListGroup>
1006
-
1007
- {/* FOOTER. */}
1008
- <View className="flex-row items-center justify-center gap-space-12 px-space-12 pb-space-8">
1009
- <Pressable onPress={menu.onPrivacy} accessibilityRole="link">
1010
- <Text className="text-bodySmall text-text-secondary">{t('accountMenu.privacy')}</Text>
1011
- </Pressable>
1012
- <Text className="text-bodySmall text-text-tertiary">·</Text>
1013
- <Pressable onPress={menu.onTerms} accessibilityRole="link">
1014
- <Text className="text-bodySmall text-text-secondary">{t('accountMenu.terms')}</Text>
1015
- </Pressable>
1016
- </View>
1017
- </View>
1018
- );
1019
- };
1020
-
1021
- // ---------------------------------------------------------------------------
1022
- // Account-menu row building blocks (NativeWind)
1023
- // ---------------------------------------------------------------------------
1024
-
1025
- /**
1026
- * An account-list AFFORDANCE row ("Add another account", "Manage accounts on
1027
- * this device") — a bordered circle sized to the avatar it stands in for, so its
1028
- * label lands on the same line as every account name above it. Own markup, like
1029
- * the account rows it closes: this list is not a Bloom grouped section.
1030
- */
1031
- const AccountAffordanceRow: React.FC<{
1032
- icon: keyof typeof MaterialCommunityIcons.glyphMap;
1033
- label: string;
1034
- onPress: () => void;
1035
- disabled?: boolean;
1036
- theme: Theme;
1037
- }> = ({ icon, label, onPress, disabled, theme }) => (
1038
- <HoverPressable
1039
- baseClassName={`flex-row items-center gap-space-12 px-space-12 py-[10px]${
1040
- disabled ? ' opacity-60' : ''
1041
- }`}
1042
- hoverClassName="bg-fill-secondary"
1043
- onPress={onPress}
1044
- disabled={disabled}
1045
- accessibilityRole="button"
1046
- accessibilityLabel={label}
1047
- >
1048
- <View className="w-[36px] h-[36px] items-center justify-center rounded-radius-max border border-border">
1049
- <MaterialCommunityIcons name={icon} size={BADGE_GLYPH_SIZE} color={theme.colors.textSecondary} />
1050
- </View>
1051
- <Text className="flex-1 text-body font-semibold text-text" numberOfLines={1}>
1052
- {label}
1053
- </Text>
1054
- </HoverPressable>
1055
- );
1056
-
1057
- /**
1058
- * The leading glyph for a grouped-section menu row, sized to Bloom's 20px icon
1059
- * column so the icons, the storage block's cloud and every row title align.
1060
- */
1061
- const MenuIcon: React.FC<{
1062
- name: keyof typeof MaterialCommunityIcons.glyphMap;
1063
- theme: Theme;
1064
- }> = ({ name, theme }) => (
1065
- <MaterialCommunityIcons name={name} size={ROW_ICON_SIZE} color={theme.colors.textSecondary} />
1066
- );
1067
-
1068
- /** A storage action chip — a bordered pill on the sheet background. */
1069
- const StorageChip: React.FC<{ label: string; onPress: () => void }> = ({ label, onPress }) => (
1070
- <HoverPressable
1071
- baseClassName="rounded-radius-max border border-border bg-bg py-[9px] px-[14px]"
1072
- hoverClassName="bg-fill-secondary"
1073
- onPress={onPress}
1074
- accessibilityRole="button"
1075
- accessibilityLabel={label}
1076
- >
1077
- <Text className="text-bodySmall font-semibold text-text">{label}</Text>
1078
- </HoverPressable>
1079
- );
1080
-
1081
- interface AccountRowProps {
1082
- account: SwitchableAccount;
1083
- theme: Theme;
1084
- switching: boolean;
1085
- disabled: boolean;
1086
- onPress: () => void;
1087
- }
1088
-
1089
- const AccountRow: React.FC<AccountRowProps> = ({ account, theme, switching, disabled, onPress }) => {
1090
- const accent = resolveAccentHex(account.color, theme.colors.primary);
1091
- const rowStyle: StyleProp<ViewStyle> = [
1092
- styles.accountRow,
1093
- {
1094
- borderColor: account.isCurrent ? accent : theme.colors.border,
1095
- backgroundColor: theme.colors.card,
1096
- },
1097
- disabled && !switching ? styles.rowDisabled : null,
1098
- ];
1099
-
1100
- return (
1101
- <BloomColorScope colorPreset={toPreset(account.color)} asChild>
1102
- <Pressable
1103
- style={rowStyle}
1104
- onPress={onPress}
1105
- disabled={disabled}
1106
- accessibilityRole="button"
1107
- accessibilityState={{ selected: account.isCurrent, disabled }}
1108
- accessibilityLabel={account.displayName}
1109
- >
1110
- <View style={[styles.avatarRing, { borderColor: account.isCurrent ? accent : 'transparent' }]}>
1111
- <Avatar
1112
- source={account.avatarUrl ?? undefined}
1113
- variant="thumb"
1114
- name={account.displayName}
1115
- size={ROW_AVATAR_SIZE}
1116
- />
1117
- </View>
1118
- <View style={styles.rowMeta}>
1119
- <Text style={[styles.rowName, { color: theme.colors.text }]} numberOfLines={1}>
1120
- {account.displayName}
1121
- </Text>
1122
- {account.email ? (
1123
- <Text style={[styles.rowHandle, { color: theme.colors.textSecondary }]} numberOfLines={1}>
1124
- {account.email}
1125
- </Text>
1126
- ) : null}
1127
- </View>
1128
- {switching ? (
1129
- <MaterialCommunityIcons name="loading" size={20} color={accent} />
1130
- ) : account.isCurrent ? (
1131
- <MaterialCommunityIcons name="check-circle" size={20} color={accent} />
1132
- ) : (
1133
- <MaterialCommunityIcons name="chevron-right" size={20} color={theme.colors.textSecondary} />
1134
- )}
1135
- </Pressable>
1136
- </BloomColorScope>
1137
- );
1138
- };
1139
-
1140
- // ---------------------------------------------------------------------------
1141
- // Sign-in view (add / signin) — NATIVE-facing today: on web `autoStartSignIn`
1142
- // (fired from the subscribe pass / the add / back-to-sign-in handlers) moves the
1143
- // view to `qr` almost immediately, so this renders only for a brief instant there.
1144
- // ---------------------------------------------------------------------------
1145
-
1146
- interface SignInViewProps {
1147
- snapshot: AccountDialogSnapshot;
1148
- theme: Theme;
1149
- t: Translate;
1150
- handlers: OxyAuthChooserHandlers;
1151
- onSignInWithOxy: () => void;
1152
- onScanQr: () => void;
1153
- onCreateAccount: () => void;
1154
- }
1155
-
1156
- const SignInView: React.FC<SignInViewProps> = ({
1157
- snapshot,
1158
- theme,
1159
- t,
1160
- handlers,
1161
- onSignInWithOxy,
1162
- onScanQr,
1163
- onCreateAccount,
1164
- }) => (
1165
- <View style={styles.signInBlock}>
1166
- {snapshot.accounts.length > 0 ? (
1167
- <View style={styles.rows}>
1168
- {snapshot.accounts.map((account) => (
1169
- <AccountRow
1170
- key={account.accountId}
1171
- account={account}
1172
- theme={theme}
1173
- switching={snapshot.switchingAccountId === account.accountId}
1174
- disabled={snapshot.switchingAccountId !== null}
1175
- onPress={() => handlers.onSwitch(account.accountId)}
1176
- />
1177
- ))}
1178
- <Dividerish theme={theme} label={t('signin.or') || 'or'} />
1179
- </View>
1180
- ) : null}
1181
-
1182
- <Button variant="primary" onPress={onSignInWithOxy} style={styles.primaryButton}>
1183
- {t('accountSwitcher.signInWithOxy') || 'Sign in with Oxy'}
1184
- </Button>
1185
-
1186
- <Button variant="secondary" onPress={onScanQr} style={styles.secondaryButton}>
1187
- {t('accountSwitcher.scanQr') || 'Scan a QR from another device'}
1188
- </Button>
1189
-
1190
- <SignUpFooterLink theme={theme} t={t} onPress={onCreateAccount} />
1191
- </View>
1192
- );
1193
-
1194
- const Dividerish: React.FC<{ theme: Theme; label: string }> = ({ theme, label }) => (
1195
- <View style={styles.dividerRow}>
1196
- <View style={[styles.dividerLine, { backgroundColor: theme.colors.border }]} />
1197
- <Text style={[styles.dividerText, { color: theme.colors.textSecondary }]}>{label}</Text>
1198
- <View style={[styles.dividerLine, { backgroundColor: theme.colors.border }]} />
1199
- </View>
1200
- );
1201
-
1202
- /** "New to Oxy? Create one" — shared by `SignInView` and `QrView`. */
1203
- const SignUpFooterLink: React.FC<{ theme: Theme; t: Translate; onPress: () => void }> = ({
1204
- theme,
1205
- t,
1206
- onPress,
1207
- }) => (
1208
- <Pressable onPress={onPress} accessibilityRole="button" style={styles.footerLink}>
1209
- <Text style={[styles.linkText, { color: theme.colors.textSecondary }]}>
1210
- {t('signin.createAccountLink') || 'New to Oxy? Create one'}
1211
- </Text>
1212
- </Pressable>
1213
- );
1214
-
1215
- /** "Already have an account? Sign in" — used by `SignUpView`. */
1216
- const SignInFooterLink: React.FC<{ theme: Theme; t: Translate; onPress: () => void }> = ({
1217
- theme,
1218
- t,
1219
- onPress,
1220
- }) => (
1221
- <Pressable onPress={onPress} accessibilityRole="button" style={styles.footerLink}>
1222
- <Text style={[styles.linkText, { color: theme.colors.textSecondary }]}>
1223
- {t('signup.backToSignInLink') || 'Already have an account? Sign in'}
1224
- </Text>
1225
- </Pressable>
1226
- );
1227
-
1228
- // ---------------------------------------------------------------------------
1229
- // QR view — the PRIMARY web sign-in surface, and the ONLY sign-in surface on
1230
- // native. Commons is ALWAYS the priority path (owner mandate): the QR here
1231
- // and the "Get Commons" CTA below are the leading content everywhere they
1232
- // appear. The passkey link is explicitly the lightweight, de-emphasized
1233
- // alternative for someone who doesn't want to install Commons — same visual
1234
- // subordination (a small text link, never a button) and the same "No
1235
- // Commons?" framing in its copy wherever it's offered.
1236
- // ---------------------------------------------------------------------------
1237
-
1238
- interface QrViewProps {
1239
- snapshot: AccountDialogSnapshot;
1240
- theme: Theme;
1241
- t: Translate;
1242
- onRetry: () => void;
1243
- passkeyAvailable: boolean;
1244
- onSignInWithPasskey: () => void;
1245
- passkeyPending: boolean;
1246
- onCreateAccount: () => void;
1247
- }
1248
-
1249
- const QrView: React.FC<QrViewProps> = ({
1250
- snapshot,
1251
- theme,
1252
- t,
1253
- onRetry,
1254
- passkeyAvailable,
1255
- onSignInWithPasskey,
1256
- passkeyPending,
1257
- onCreateAccount,
1258
- }) => {
1259
- const { signIn, commonsAvailability } = snapshot;
1260
- const [showQrAnyway, setShowQrAnyway] = useState(false);
1261
-
1262
- // A ceremony FAILURE is surfaced as a toast by `handleSignInWithPasskey` — the
1263
- // link itself never renders an inline error (owner mandate).
1264
- const passkeyLink =
1265
- passkeyAvailable && signIn.phase !== 'authorized' ? (
1266
- <Pressable
1267
- onPress={onSignInWithPasskey}
1268
- disabled={passkeyPending}
1269
- accessibilityRole="button"
1270
- style={styles.footerLink}
1271
- testID="passkey-signin-link"
1272
- >
1273
- <Text style={[styles.linkText, { color: theme.colors.textSecondary }]}>
1274
- {passkeyPending
1275
- ? t('accountSwitcher.passkeySigningIn') || 'Signing in…'
1276
- : t('accountSwitcher.useIdentityOnDevice') || 'No Commons? Use a passkey on this device instead'}
1277
- </Text>
1278
- </Pressable>
1279
- ) : null;
1280
-
1281
- // Native, Commons confirmed NOT installed: a same-device QR is a dead
1282
- // end (the user can't scan their own screen) — lead with "Get Commons"
1283
- // instead, and demote the QR to an explicit "I have it elsewhere" reveal.
1284
- if (commonsAvailability === 'unavailable' && !showQrAnyway) {
1285
- return (
1286
- <View style={styles.centeredBlock}>
1287
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>
1288
- {t('accountSwitcher.commonsNotInstalled') ||
1289
- "Don't have Commons? Get the app to sign in with your Oxy ID."}
1290
- </Text>
1291
- <Button
1292
- variant="primary"
1293
- onPress={() => void Linking.openURL(getCommonsAcquisitionUrl(Platform.OS))}
1294
- style={styles.primaryButton}
1295
- >
1296
- {t('accountSwitcher.getCommons') || 'Get Commons'}
1297
- </Button>
1298
- <Pressable onPress={() => setShowQrAnyway(true)} accessibilityRole="button" style={styles.footerLink}>
1299
- <Text style={[styles.linkText, { color: theme.colors.textSecondary }]}>
1300
- {t('accountSwitcher.showQrAnyway') || 'I have Commons on another device'}
1301
- </Text>
1302
- </Pressable>
1303
- {passkeyLink}
1304
- <SignUpFooterLink theme={theme} t={t} onPress={onCreateAccount} />
1305
- </View>
1306
- );
1307
- }
1308
-
1309
- if (signIn.phase === 'error') {
1310
- // The failure reason is toasted by the controller subscription above — no
1311
- // inline error copy here (owner mandate).
1312
- return (
1313
- <View style={styles.centeredBlock}>
1314
- <Button variant="secondary" onPress={onRetry} style={styles.secondaryButton}>
1315
- {t('common.actions.tryAgain') || 'Try again'}
1316
- </Button>
1317
- {passkeyLink}
1318
- </View>
1319
- );
1320
- }
1321
-
1322
- if (signIn.phase === 'starting' || signIn.phase === 'authorized' || !signIn.qrPayload) {
1323
- const label =
1324
- signIn.phase === 'authorized'
1325
- ? t('signin.status.signingIn') || 'Signing in…'
1326
- : t('accountSwitcher.loading') || 'Preparing sign-in…';
1327
- return (
1328
- <View style={styles.centeredBlock}>
1329
- <MaterialCommunityIcons name="loading" size={26} color={theme.colors.primary} />
1330
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>{label}</Text>
1331
- </View>
1332
- );
1333
- }
1334
-
1335
- return (
1336
- <View style={styles.centeredBlock}>
1337
- <Text style={[styles.qrHeadline, { color: theme.colors.text }]}>
1338
- {t('accountSwitcher.qrHeadline') || 'Sign in with your Oxy identity'}
1339
- </Text>
1340
- <View style={styles.qrPlate}>
1341
- <QRCode value={signIn.qrPayload} size={QR_SIZE} backgroundColor={QR_PLATE_BG} color={QR_FOREGROUND} />
1342
- </View>
1343
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>
1344
- {t('accountSwitcher.scanWithOxy') || 'Scan with Commons on your phone to continue.'}
1345
- </Text>
1346
- {passkeyLink}
1347
- <SignUpFooterLink theme={theme} t={t} onPress={onCreateAccount} />
1348
- </View>
1349
- );
1350
- };
1351
-
1352
- // ---------------------------------------------------------------------------
1353
- // Sign-up view
1354
- // ---------------------------------------------------------------------------
1355
-
1356
- type UsernameStatus = 'idle' | 'checking' | 'available' | 'taken';
1357
-
1358
- /** Debounced username-availability check over the existing SDK method. */
1359
- function useUsernameAvailability(
1360
- oxyServices: OxyServices,
1361
- t: Translate,
1362
- ): {
1363
- status: UsernameStatus;
1364
- check: (value: string) => void;
1365
- } {
1366
- const [status, setStatus] = useState<UsernameStatus>('idle');
1367
- const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
1368
- const requestSeqRef = useRef(0);
1369
-
1370
- const check = useCallback(
1371
- (value: string) => {
1372
- if (timerRef.current) clearTimeout(timerRef.current);
1373
- const seq = ++requestSeqRef.current;
1374
- if (!value || value.length < 3) {
1375
- setStatus('idle');
1376
- return;
1377
- }
1378
- setStatus('checking');
1379
- timerRef.current = setTimeout(() => {
1380
- void oxyServices
1381
- .checkUsernameAvailability(value)
1382
- .then((result) => {
1383
- if (seq !== requestSeqRef.current) return; // superseded by a newer check
1384
- setStatus(result.available ? 'available' : 'taken');
1385
- })
1386
- .catch(() => {
1387
- if (seq !== requestSeqRef.current) return;
1388
- // Reset the (now stale) verdict rather than block on it, and surface
1389
- // the failure as a toast — never an inline error inside the dialog.
1390
- setStatus('idle');
1391
- toast.error(
1392
- t('accounts.create.username.checkFailed') || 'Could not check availability',
1393
- );
1394
- });
1395
- }, 400);
1396
- },
1397
- [oxyServices, t],
1398
- );
1399
-
1400
- return { status, check };
1401
- }
1402
-
1403
- const UsernameStatusText: React.FC<{ status: UsernameStatus; theme: Theme; t: Translate }> = ({
1404
- status,
1405
- theme,
1406
- t,
1407
- }) => {
1408
- if (status === 'idle') return null;
1409
- if (status === 'checking') {
1410
- return (
1411
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>
1412
- {t('signup.usernameChecking') || 'Checking…'}
1413
- </Text>
1414
- );
1415
- }
1416
- if (status === 'available') {
1417
- return (
1418
- <Text style={[styles.mutedText, { color: theme.colors.success }]}>
1419
- {t('signup.usernameAvailable') || 'Available'}
1420
- </Text>
1421
- );
1422
- }
1423
- return (
1424
- <Text style={[styles.mutedText, { color: theme.colors.error }]}>
1425
- {t('signup.usernameTaken') || 'This username is taken'}
1426
- </Text>
1427
- );
1428
- };
1429
-
1430
- interface SignUpViewProps {
1431
- snapshot: AccountDialogSnapshot;
1432
- theme: Theme;
1433
- t: Translate;
1434
- oxyServices: OxyServices;
1435
- passkeyMode: 'direct' | 'hub' | 'none';
1436
- onCreateWithPasskey: (username: string) => Promise<void>;
1437
- createPending: boolean;
1438
- /** Open the auth.oxy.so hub popup (b2) — the 'hub' mode's only path. */
1439
- onOpenHub: () => void;
1440
- onBackToSignIn: () => void;
1441
- }
1442
-
1443
- const SignUpView: React.FC<SignUpViewProps> = ({
1444
- snapshot,
1445
- theme,
1446
- t,
1447
- oxyServices,
1448
- passkeyMode,
1449
- onCreateWithPasskey,
1450
- createPending,
1451
- onOpenHub,
1452
- onBackToSignIn,
1453
- }) => {
1454
- const [username, setUsername] = useState('');
1455
- const { status: usernameStatus, check: checkUsername } = useUsernameAvailability(oxyServices, t);
1456
- const canSubmit = username.trim().length >= 3 && usernameStatus === 'available' && !createPending;
1457
-
1458
- // Native — Commons owns identity creation. Mirrors the QR view's own
1459
- // commonsAvailability branch: deep-link straight in when installed, else
1460
- // lead with the same "Get Commons" fallback.
1461
- if (!isWebBrowser()) {
1462
- const commonsInstalled = snapshot.commonsAvailability === 'available';
1463
- return (
1464
- <View style={styles.centeredBlock}>
1465
- <Button
1466
- variant="primary"
1467
- onPress={() =>
1468
- void Linking.openURL(
1469
- commonsInstalled ? COMMONS_CREATE_IDENTITY_URL : getCommonsAcquisitionUrl(Platform.OS),
1470
- )
1471
- }
1472
- style={styles.primaryButton}
1473
- >
1474
- {commonsInstalled
1475
- ? t('signup.createInCommons') || 'Create your identity in Commons'
1476
- : t('accountSwitcher.getCommons') || 'Get Commons'}
1477
- </Button>
1478
- <SignInFooterLink theme={theme} t={t} onPress={onBackToSignIn} />
1479
- </View>
1480
- );
1481
- }
1482
-
1483
- // Web, first-party Oxy origin. Commons leads (owner mandate: it's ALWAYS
1484
- // the priority path, everywhere the two appear) with a "Get Commons" CTA;
1485
- // passkey creation is the de-emphasized alternative underneath for someone
1486
- // who doesn't want to install anything — secondary button, introduced by
1487
- // its own "No Commons?" framing, same subordination as the QR view's link.
1488
- if (passkeyMode === 'direct') {
1489
- return (
1490
- <View style={styles.signInBlock}>
1491
- <Text style={[styles.qrHeadline, { color: theme.colors.text }]}>
1492
- {t('signup.commonsHeadline') || 'Create your identity in Commons'}
1493
- </Text>
1494
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>
1495
- {t('signup.commonsExplainer') ||
1496
- 'Commons is your full self-custody Oxy identity — one app, works everywhere.'}
1497
- </Text>
1498
- <Button
1499
- variant="primary"
1500
- onPress={() => void Linking.openURL(getCommonsAcquisitionUrl(Platform.OS))}
1501
- style={styles.primaryButton}
1502
- >
1503
- {t('accountSwitcher.getCommons') || 'Get Commons'}
1504
- </Button>
1505
-
1506
- <Dividerish theme={theme} label={t('signin.or') || 'or'} />
1507
-
1508
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>
1509
- {t('signup.passkeyAlternative') || "No Commons? Create a passkey on this device instead"}
1510
- </Text>
1511
- <TextInput
1512
- style={[styles.usernameInput, { borderColor: theme.colors.border, color: theme.colors.text }]}
1513
- placeholder={t('signup.usernamePlaceholder') || 'Choose a username'}
1514
- placeholderTextColor={theme.colors.textSecondary}
1515
- value={username}
1516
- autoCapitalize="none"
1517
- autoCorrect={false}
1518
- autoComplete="username"
1519
- onChangeText={(value) => {
1520
- setUsername(value);
1521
- checkUsername(value.trim());
1522
- }}
1523
- testID="signup-username-input"
1524
- />
1525
- <UsernameStatusText status={usernameStatus} theme={theme} t={t} />
1526
- <Button
1527
- variant="secondary"
1528
- onPress={() => void onCreateWithPasskey(username.trim())}
1529
- disabled={!canSubmit}
1530
- style={styles.secondaryButton}
1531
- testID="signup-create-button"
1532
- >
1533
- {createPending
1534
- ? t('signup.creating') || 'Creating…'
1535
- : t('signup.createAccount') || 'Create account'}
1536
- </Button>
1537
- <SignInFooterLink theme={theme} t={t} onPress={onBackToSignIn} />
1538
- </View>
1539
- );
1540
- }
1541
-
1542
- // Web, non-Oxy origin (b2): passkey creation can't run locally here — the
1543
- // same WebAuthn RP-ID boundary as sign-in — so this opens the SAME
1544
- // auth.oxy.so passkey hub popup `QrView`'s "No Commons?" link uses.
1545
- // Completing EITHER a sign-in OR a fresh sign-up there relays the resulting
1546
- // session back via the SAME poll/socket engine `showQr` drives.
1547
- return (
1548
- <View style={styles.centeredBlock}>
1549
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>
1550
- {t('signup.hubExplainer') ||
1551
- 'Create your Oxy ID in a secure window, then come right back.'}
1552
- </Text>
1553
- <Button variant="primary" onPress={onOpenHub} style={styles.primaryButton}>
1554
- {t('signup.continueInWindow') || 'Continue in a new window'}
1555
- </Button>
1556
- <SignInFooterLink theme={theme} t={t} onPress={onBackToSignIn} />
1557
- </View>
1558
- );
1559
- };
1560
-
1561
411
  // ---------------------------------------------------------------------------
1562
412
  // Empty snapshot (no-provider loading state)
1563
413
  // ---------------------------------------------------------------------------
@@ -1569,7 +419,18 @@ const EMPTY_SNAPSHOT: AccountDialogSnapshot = {
1569
419
  loading: false,
1570
420
  error: null,
1571
421
  switchingAccountId: null,
1572
- signIn: { phase: 'idle', authorizeCode: null, qrPayload: null, expiresAt: null, error: null },
422
+ signIn: {
423
+ phase: 'idle',
424
+ authorizeCode: null,
425
+ qrPayload: null,
426
+ expiresAt: null,
427
+ error: null,
428
+ route: null,
429
+ routeFailed: false,
430
+ pushSentAt: null,
431
+ openedAt: null,
432
+ progress: 'idle',
433
+ },
1573
434
  commonsAvailability: 'unknown',
1574
435
  };
1575
436