@oxy.so/services 4.0.6 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/README.md +1 -1
  2. package/lib/commonjs/assets/assets/signIn/slide-1.jpg +0 -0
  3. package/lib/commonjs/assets/assets/signIn/slide-1.jpg.d.ts +3 -0
  4. package/lib/commonjs/assets/assets/signIn/slide-2.jpg +0 -0
  5. package/lib/commonjs/assets/assets/signIn/slide-2.jpg.d.ts +3 -0
  6. package/lib/commonjs/assets/assets/signIn/slide-3.jpg +0 -0
  7. package/lib/commonjs/assets/assets/signIn/slide-3.jpg.d.ts +3 -0
  8. package/lib/commonjs/assets/assets/signIn/slide-4.jpg +0 -0
  9. package/lib/commonjs/assets/assets/signIn/slide-4.jpg.d.ts +3 -0
  10. package/lib/commonjs/assets/signIn/slide-1.jpg +0 -0
  11. package/lib/commonjs/assets/signIn/slide-2.jpg +0 -0
  12. package/lib/commonjs/assets/signIn/slide-3.jpg +0 -0
  13. package/lib/commonjs/assets/signIn/slide-4.jpg +0 -0
  14. package/lib/commonjs/index.js +45 -8
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/commonjs/ui/components/FollowButton.js +26 -1
  17. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  18. package/lib/commonjs/ui/components/FollowTargetButton.js +6 -1
  19. package/lib/commonjs/ui/components/FollowTargetButton.js.map +1 -1
  20. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +11 -58
  21. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
  22. package/lib/commonjs/ui/components/OxyAuthChooser.js +36 -44
  23. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  24. package/lib/commonjs/ui/components/OxyProvider.js +0 -2
  25. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  26. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  27. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +29 -8
  28. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  29. package/lib/commonjs/ui/components/authChooser/primitives.js +7 -52
  30. package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
  31. package/lib/commonjs/ui/components/authChooser/signInFailureMessage.js +1 -7
  32. package/lib/commonjs/ui/components/authChooser/signInFailureMessage.js.map +1 -1
  33. package/lib/commonjs/ui/components/authChooser/styles.js +0 -31
  34. package/lib/commonjs/ui/components/authChooser/styles.js.map +1 -1
  35. package/lib/commonjs/ui/components/authChooser/types.js +2 -2
  36. package/lib/commonjs/ui/components/followButtonAccessibility.js +72 -0
  37. package/lib/commonjs/ui/components/followButtonAccessibility.js.map +1 -0
  38. package/lib/commonjs/ui/components/oauthNavigation.js +1 -1
  39. package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js +161 -0
  40. package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js.map +1 -0
  41. package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js +111 -0
  42. package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js.map +1 -0
  43. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js +160 -0
  44. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js.map +1 -0
  45. package/lib/commonjs/ui/components/signIn/OxySignInPanel.js +371 -0
  46. package/lib/commonjs/ui/components/signIn/OxySignInPanel.js.map +1 -0
  47. package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js +78 -0
  48. package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js.map +1 -0
  49. package/lib/commonjs/ui/components/signIn/artwork.js +21 -0
  50. package/lib/commonjs/ui/components/signIn/artwork.js.map +1 -0
  51. package/lib/commonjs/ui/components/signIn/passkeyError.js +46 -0
  52. package/lib/commonjs/ui/components/signIn/passkeyError.js.map +1 -0
  53. package/lib/commonjs/ui/components/signIn/signInMethods.js +46 -0
  54. package/lib/commonjs/ui/components/signIn/signInMethods.js.map +1 -0
  55. package/lib/commonjs/ui/context/OxyContext.js +16 -16
  56. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  57. package/lib/commonjs/ui/context/commitSessionFlow.js +0 -43
  58. package/lib/commonjs/ui/context/commitSessionFlow.js.map +1 -1
  59. package/lib/commonjs/ui/hooks/accountDialogSnapshot.js +15 -1
  60. package/lib/commonjs/ui/hooks/accountDialogSnapshot.js.map +1 -1
  61. package/lib/commonjs/ui/hooks/useDeviceSwitcher.js +1 -3
  62. package/lib/commonjs/ui/hooks/useDeviceSwitcher.js.map +1 -1
  63. package/lib/commonjs/ui/oauth/browserAuthTransport.js +11 -4
  64. package/lib/commonjs/ui/oauth/browserAuthTransport.js.map +1 -1
  65. package/lib/commonjs/ui/oauth/oauthHandshake.js +3 -0
  66. package/lib/commonjs/ui/oauth/oauthHandshake.js.map +1 -1
  67. package/lib/commonjs/ui/oauth/oauthPopup.js +2 -3
  68. package/lib/commonjs/ui/oauth/oauthPopup.js.map +1 -1
  69. package/lib/commonjs/ui/screens/ManageAccountScreen.js +2 -3
  70. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  71. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +1 -1
  72. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  73. package/lib/commonjs/ui/session/authStore.js +0 -21
  74. package/lib/commonjs/ui/session/authStore.js.map +1 -1
  75. package/lib/commonjs/ui/utils/accountDeletionHandoff.js +1 -1
  76. package/lib/commonjs/ui/utils/accountDeletionHandoff.js.map +1 -1
  77. package/lib/module/assets/assets/signIn/slide-1.jpg +0 -0
  78. package/lib/module/assets/assets/signIn/slide-1.jpg.d.ts +3 -0
  79. package/lib/module/assets/assets/signIn/slide-2.jpg +0 -0
  80. package/lib/module/assets/assets/signIn/slide-2.jpg.d.ts +3 -0
  81. package/lib/module/assets/assets/signIn/slide-3.jpg +0 -0
  82. package/lib/module/assets/assets/signIn/slide-3.jpg.d.ts +3 -0
  83. package/lib/module/assets/assets/signIn/slide-4.jpg +0 -0
  84. package/lib/module/assets/assets/signIn/slide-4.jpg.d.ts +3 -0
  85. package/lib/module/assets/signIn/slide-1.jpg +0 -0
  86. package/lib/module/assets/signIn/slide-2.jpg +0 -0
  87. package/lib/module/assets/signIn/slide-3.jpg +0 -0
  88. package/lib/module/assets/signIn/slide-4.jpg +0 -0
  89. package/lib/module/index.js +7 -6
  90. package/lib/module/index.js.map +1 -1
  91. package/lib/module/ui/components/FollowButton.js +26 -1
  92. package/lib/module/ui/components/FollowButton.js.map +1 -1
  93. package/lib/module/ui/components/FollowTargetButton.js +6 -1
  94. package/lib/module/ui/components/FollowTargetButton.js.map +1 -1
  95. package/lib/module/ui/components/OxyAccountDialogScreen.js +14 -59
  96. package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
  97. package/lib/module/ui/components/OxyAuthChooser.js +37 -45
  98. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  99. package/lib/module/ui/components/OxyProvider.js +0 -2
  100. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  101. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  102. package/lib/module/ui/components/authChooser/AccountsMenuView.js +21 -2
  103. package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  104. package/lib/module/ui/components/authChooser/primitives.js +1 -44
  105. package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
  106. package/lib/module/ui/components/authChooser/signInFailureMessage.js +1 -7
  107. package/lib/module/ui/components/authChooser/signInFailureMessage.js.map +1 -1
  108. package/lib/module/ui/components/authChooser/styles.js +0 -31
  109. package/lib/module/ui/components/authChooser/styles.js.map +1 -1
  110. package/lib/module/ui/components/authChooser/types.js +2 -2
  111. package/lib/module/ui/components/followButtonAccessibility.js +66 -0
  112. package/lib/module/ui/components/followButtonAccessibility.js.map +1 -0
  113. package/lib/module/ui/components/oauthNavigation.js +1 -1
  114. package/lib/module/ui/components/signIn/InlineCommonsQr.js +157 -0
  115. package/lib/module/ui/components/signIn/InlineCommonsQr.js.map +1 -0
  116. package/lib/module/ui/components/signIn/OxyAccountPicker.js +106 -0
  117. package/lib/module/ui/components/signIn/OxyAccountPicker.js.map +1 -0
  118. package/lib/module/ui/components/signIn/OxyAuthScreen.js +151 -0
  119. package/lib/module/ui/components/signIn/OxyAuthScreen.js.map +1 -0
  120. package/lib/module/ui/components/signIn/OxySignInPanel.js +366 -0
  121. package/lib/module/ui/components/signIn/OxySignInPanel.js.map +1 -0
  122. package/lib/module/ui/components/signIn/OxySignUpPanel.js +75 -0
  123. package/lib/module/ui/components/signIn/OxySignUpPanel.js.map +1 -0
  124. package/lib/module/ui/components/signIn/artwork.js +16 -0
  125. package/lib/module/ui/components/signIn/artwork.js.map +1 -0
  126. package/lib/module/ui/components/signIn/passkeyError.js +40 -0
  127. package/lib/module/ui/components/signIn/passkeyError.js.map +1 -0
  128. package/lib/module/ui/components/signIn/signInMethods.js +42 -0
  129. package/lib/module/ui/components/signIn/signInMethods.js.map +1 -0
  130. package/lib/module/ui/context/OxyContext.js +17 -17
  131. package/lib/module/ui/context/OxyContext.js.map +1 -1
  132. package/lib/module/ui/context/commitSessionFlow.js +0 -42
  133. package/lib/module/ui/context/commitSessionFlow.js.map +1 -1
  134. package/lib/module/ui/hooks/accountDialogSnapshot.js +14 -1
  135. package/lib/module/ui/hooks/accountDialogSnapshot.js.map +1 -1
  136. package/lib/module/ui/hooks/useDeviceSwitcher.js +3 -5
  137. package/lib/module/ui/hooks/useDeviceSwitcher.js.map +1 -1
  138. package/lib/module/ui/oauth/browserAuthTransport.js +11 -4
  139. package/lib/module/ui/oauth/browserAuthTransport.js.map +1 -1
  140. package/lib/module/ui/oauth/oauthHandshake.js +3 -0
  141. package/lib/module/ui/oauth/oauthHandshake.js.map +1 -1
  142. package/lib/module/ui/oauth/oauthPopup.js +2 -3
  143. package/lib/module/ui/oauth/oauthPopup.js.map +1 -1
  144. package/lib/module/ui/screens/ManageAccountScreen.js +3 -4
  145. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  146. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +1 -1
  147. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  148. package/lib/module/ui/session/authStore.js +1 -22
  149. package/lib/module/ui/session/authStore.js.map +1 -1
  150. package/lib/module/ui/utils/accountDeletionHandoff.js +2 -2
  151. package/lib/module/ui/utils/accountDeletionHandoff.js.map +1 -1
  152. package/lib/typescript/assets/signIn/slide-1.jpg.d.ts +3 -0
  153. package/lib/typescript/assets/signIn/slide-2.jpg.d.ts +3 -0
  154. package/lib/typescript/assets/signIn/slide-3.jpg.d.ts +3 -0
  155. package/lib/typescript/assets/signIn/slide-4.jpg.d.ts +3 -0
  156. package/lib/typescript/commonjs/index.d.ts +8 -2
  157. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  158. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +6 -0
  159. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
  160. package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts.map +1 -1
  161. package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  162. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +5 -12
  163. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  164. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  165. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +1 -1
  166. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
  167. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  168. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +0 -19
  169. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -1
  170. package/lib/typescript/commonjs/ui/components/authChooser/signInFailureMessage.d.ts +1 -5
  171. package/lib/typescript/commonjs/ui/components/authChooser/signInFailureMessage.d.ts.map +1 -1
  172. package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts +0 -31
  173. package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts.map +1 -1
  174. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +3 -3
  175. package/lib/typescript/commonjs/ui/components/followButtonAccessibility.d.ts +48 -0
  176. package/lib/typescript/commonjs/ui/components/followButtonAccessibility.d.ts.map +1 -0
  177. package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts +1 -1
  178. package/lib/typescript/commonjs/ui/components/signIn/InlineCommonsQr.d.ts +20 -0
  179. package/lib/typescript/commonjs/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -0
  180. package/lib/typescript/commonjs/ui/components/signIn/OxyAccountPicker.d.ts +34 -0
  181. package/lib/typescript/commonjs/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -0
  182. package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts +43 -0
  183. package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -0
  184. package/lib/typescript/commonjs/ui/components/signIn/OxySignInPanel.d.ts +43 -0
  185. package/lib/typescript/commonjs/ui/components/signIn/OxySignInPanel.d.ts.map +1 -0
  186. package/lib/typescript/commonjs/ui/components/signIn/OxySignUpPanel.d.ts +17 -0
  187. package/lib/typescript/commonjs/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -0
  188. package/lib/typescript/commonjs/ui/components/signIn/artwork.d.ts +8 -0
  189. package/lib/typescript/commonjs/ui/components/signIn/artwork.d.ts.map +1 -0
  190. package/lib/typescript/commonjs/ui/components/signIn/passkeyError.d.ts +16 -0
  191. package/lib/typescript/commonjs/ui/components/signIn/passkeyError.d.ts.map +1 -0
  192. package/lib/typescript/commonjs/ui/components/signIn/signInMethods.d.ts +39 -0
  193. package/lib/typescript/commonjs/ui/components/signIn/signInMethods.d.ts.map +1 -0
  194. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  195. package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts +0 -40
  196. package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts.map +1 -1
  197. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +8 -9
  198. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
  199. package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts +7 -1
  200. package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts.map +1 -1
  201. package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts.map +1 -1
  202. package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts +9 -0
  203. package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts.map +1 -1
  204. package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts +3 -0
  205. package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts.map +1 -1
  206. package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts +2 -3
  207. package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts.map +1 -1
  208. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  209. package/lib/typescript/commonjs/ui/session/authStore.d.ts +0 -30
  210. package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
  211. package/lib/typescript/commonjs/ui/types/navigation.d.ts +0 -26
  212. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  213. package/lib/typescript/module/index.d.ts +8 -2
  214. package/lib/typescript/module/index.d.ts.map +1 -1
  215. package/lib/typescript/module/ui/components/FollowButton.d.ts +6 -0
  216. package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
  217. package/lib/typescript/module/ui/components/FollowTargetButton.d.ts.map +1 -1
  218. package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  219. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +5 -12
  220. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  221. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  222. package/lib/typescript/module/ui/components/ProfileButton.d.ts +1 -1
  223. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
  224. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  225. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +0 -19
  226. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -1
  227. package/lib/typescript/module/ui/components/authChooser/signInFailureMessage.d.ts +1 -5
  228. package/lib/typescript/module/ui/components/authChooser/signInFailureMessage.d.ts.map +1 -1
  229. package/lib/typescript/module/ui/components/authChooser/styles.d.ts +0 -31
  230. package/lib/typescript/module/ui/components/authChooser/styles.d.ts.map +1 -1
  231. package/lib/typescript/module/ui/components/authChooser/types.d.ts +3 -3
  232. package/lib/typescript/module/ui/components/followButtonAccessibility.d.ts +48 -0
  233. package/lib/typescript/module/ui/components/followButtonAccessibility.d.ts.map +1 -0
  234. package/lib/typescript/module/ui/components/oauthNavigation.d.ts +1 -1
  235. package/lib/typescript/module/ui/components/signIn/InlineCommonsQr.d.ts +20 -0
  236. package/lib/typescript/module/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -0
  237. package/lib/typescript/module/ui/components/signIn/OxyAccountPicker.d.ts +34 -0
  238. package/lib/typescript/module/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -0
  239. package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts +43 -0
  240. package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -0
  241. package/lib/typescript/module/ui/components/signIn/OxySignInPanel.d.ts +43 -0
  242. package/lib/typescript/module/ui/components/signIn/OxySignInPanel.d.ts.map +1 -0
  243. package/lib/typescript/module/ui/components/signIn/OxySignUpPanel.d.ts +17 -0
  244. package/lib/typescript/module/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -0
  245. package/lib/typescript/module/ui/components/signIn/artwork.d.ts +8 -0
  246. package/lib/typescript/module/ui/components/signIn/artwork.d.ts.map +1 -0
  247. package/lib/typescript/module/ui/components/signIn/passkeyError.d.ts +16 -0
  248. package/lib/typescript/module/ui/components/signIn/passkeyError.d.ts.map +1 -0
  249. package/lib/typescript/module/ui/components/signIn/signInMethods.d.ts +39 -0
  250. package/lib/typescript/module/ui/components/signIn/signInMethods.d.ts.map +1 -0
  251. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  252. package/lib/typescript/module/ui/context/commitSessionFlow.d.ts +0 -40
  253. package/lib/typescript/module/ui/context/commitSessionFlow.d.ts.map +1 -1
  254. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +8 -9
  255. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
  256. package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts +7 -1
  257. package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts.map +1 -1
  258. package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts.map +1 -1
  259. package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts +9 -0
  260. package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts.map +1 -1
  261. package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts +3 -0
  262. package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts.map +1 -1
  263. package/lib/typescript/module/ui/oauth/oauthPopup.d.ts +2 -3
  264. package/lib/typescript/module/ui/oauth/oauthPopup.d.ts.map +1 -1
  265. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  266. package/lib/typescript/module/ui/session/authStore.d.ts +0 -30
  267. package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
  268. package/lib/typescript/module/ui/types/navigation.d.ts +0 -26
  269. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  270. package/package.json +6 -9
  271. package/src/assets/signIn/slide-1.jpg +0 -0
  272. package/src/assets/signIn/slide-1.jpg.d.ts +3 -0
  273. package/src/assets/signIn/slide-2.jpg +0 -0
  274. package/src/assets/signIn/slide-2.jpg.d.ts +3 -0
  275. package/src/assets/signIn/slide-3.jpg +0 -0
  276. package/src/assets/signIn/slide-3.jpg.d.ts +3 -0
  277. package/src/assets/signIn/slide-4.jpg +0 -0
  278. package/src/assets/signIn/slide-4.jpg.d.ts +3 -0
  279. package/src/index.ts +16 -7
  280. package/src/ui/components/FollowButton.tsx +25 -0
  281. package/src/ui/components/FollowTargetButton.tsx +4 -0
  282. package/src/ui/components/OxyAccountDialogScreen.tsx +11 -72
  283. package/src/ui/components/OxyAuthChooser.tsx +37 -53
  284. package/src/ui/components/OxyProvider.tsx +0 -2
  285. package/src/ui/components/ProfileButton.tsx +1 -4
  286. package/src/ui/components/__tests__/followButtonAccessibility.test.tsx +191 -0
  287. package/src/ui/components/authChooser/AccountsMenuView.tsx +28 -1
  288. package/src/ui/components/authChooser/primitives.tsx +1 -39
  289. package/src/ui/components/authChooser/signInFailureMessage.ts +1 -7
  290. package/src/ui/components/authChooser/styles.ts +0 -31
  291. package/src/ui/components/authChooser/types.ts +3 -3
  292. package/src/ui/components/followButtonAccessibility.ts +83 -0
  293. package/src/ui/components/oauthNavigation.ts +1 -1
  294. package/src/ui/components/signIn/InlineCommonsQr.tsx +135 -0
  295. package/src/ui/components/signIn/OxyAccountPicker.tsx +129 -0
  296. package/src/ui/components/signIn/OxyAuthScreen.tsx +123 -0
  297. package/src/ui/components/signIn/OxySignInPanel.tsx +392 -0
  298. package/src/ui/components/signIn/OxySignUpPanel.tsx +86 -0
  299. package/src/ui/components/signIn/artwork.ts +13 -0
  300. package/src/ui/components/signIn/passkeyError.ts +44 -0
  301. package/src/ui/components/signIn/signInMethods.ts +51 -0
  302. package/src/ui/context/OxyContext.tsx +21 -18
  303. package/src/ui/context/__tests__/commitSessionFlow.test.ts +0 -89
  304. package/src/ui/context/commitSessionFlow.ts +0 -61
  305. package/src/ui/context/oxyContextTypes.ts +9 -9
  306. package/src/ui/hooks/accountDialogSnapshot.ts +20 -1
  307. package/src/ui/hooks/useDeviceSwitcher.ts +3 -11
  308. package/src/ui/oauth/__tests__/browserAuthTransport.test.ts +21 -0
  309. package/src/ui/oauth/browserAuthTransport.ts +14 -4
  310. package/src/ui/oauth/oauthHandshake.ts +4 -1
  311. package/src/ui/oauth/oauthPopup.ts +2 -3
  312. package/src/ui/screens/ManageAccountScreen.tsx +3 -4
  313. package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +1 -1
  314. package/src/ui/session/authStore.ts +0 -37
  315. package/src/ui/types/navigation.ts +0 -26
  316. package/src/ui/utils/accountDeletionHandoff.ts +2 -2
  317. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js +0 -132
  318. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js.map +0 -1
  319. package/lib/commonjs/ui/components/authChooser/SignUpView.js +0 -77
  320. package/lib/commonjs/ui/components/authChooser/SignUpView.js.map +0 -1
  321. package/lib/commonjs/ui/components/passkeyHubPopup.js +0 -33
  322. package/lib/commonjs/ui/components/passkeyHubPopup.js.map +0 -1
  323. package/lib/commonjs/ui/oauth/legacyRedirectLanes.js +0 -48
  324. package/lib/commonjs/ui/oauth/legacyRedirectLanes.js.map +0 -1
  325. package/lib/module/ui/components/authChooser/SignInEntryView.js +0 -127
  326. package/lib/module/ui/components/authChooser/SignInEntryView.js.map +0 -1
  327. package/lib/module/ui/components/authChooser/SignUpView.js +0 -73
  328. package/lib/module/ui/components/authChooser/SignUpView.js.map +0 -1
  329. package/lib/module/ui/components/passkeyHubPopup.js +0 -29
  330. package/lib/module/ui/components/passkeyHubPopup.js.map +0 -1
  331. package/lib/module/ui/oauth/legacyRedirectLanes.js +0 -44
  332. package/lib/module/ui/oauth/legacyRedirectLanes.js.map +0 -1
  333. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts +0 -39
  334. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts.map +0 -1
  335. package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts +0 -31
  336. package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts.map +0 -1
  337. package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts +0 -23
  338. package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts.map +0 -1
  339. package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts +0 -40
  340. package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
  341. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts +0 -39
  342. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts.map +0 -1
  343. package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts +0 -31
  344. package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts.map +0 -1
  345. package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts +0 -23
  346. package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts.map +0 -1
  347. package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts +0 -40
  348. package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
  349. package/src/ui/components/authChooser/SignInEntryView.tsx +0 -157
  350. package/src/ui/components/authChooser/SignUpView.tsx +0 -76
  351. package/src/ui/components/passkeyHubPopup.ts +0 -28
  352. package/src/ui/oauth/legacyRedirectLanes.ts +0 -43
@@ -0,0 +1,129 @@
1
+ /**
2
+ * "Choose an account" — every `principal acting as account` pair on this
3
+ * device, then "Use another account".
4
+ *
5
+ * The front screen of sign-in on a returning device, in the account dialog and
6
+ * on every auth.oxy.so page that asks WHO (sign-in, OAuth authorize, device
7
+ * approval, MCP linking). Presentational: the host decides what choosing a row
8
+ * means — a switch, a "Continue as" sign-in, or activating the pair before an
9
+ * OAuth consent — and passes the pair back, never an account id, which cannot
10
+ * say whose route was chosen.
11
+ */
12
+
13
+ import type React from 'react';
14
+ import { Pressable, StyleSheet, View } from 'react-native';
15
+ import { RiArrowRightSLine } from '@oxy.so/bloom/icons/RiArrowRightSLine';
16
+ import { RiUserAddLine } from '@oxy.so/bloom/icons/RiUserAddLine';
17
+ import { useTheme } from '@oxy.so/bloom/theme';
18
+ import { Text } from '@oxy.so/bloom/typography';
19
+ import { showsPrincipalHeaders, type SwitcherContextRow, type SwitcherPrincipalRow } from '@oxy.so/core';
20
+ import { useI18n } from '../../hooks/useI18n';
21
+ import { AccountRow } from '../authChooser/primitives';
22
+ import { authChooserStyles } from '../authChooser/styles';
23
+ import { OxyAuthScreen, OxyAuthScreenHeader, OxyAuthTerms } from './OxyAuthScreen';
24
+
25
+ export interface OxyAccountPickerProps {
26
+ /** The device's people, each with the accounts they may act as (`useDeviceSwitcher`). */
27
+ principals: SwitcherPrincipalRow[];
28
+ /** The app being continued to, when there is one. */
29
+ appName?: string | null;
30
+ onSelectContext: (context: SwitcherContextRow) => void;
31
+ /** "Use another account" — the host reveals its sign-in. */
32
+ onUseAnother: () => void;
33
+ /** The pair being activated, whose row shows it is busy. */
34
+ pendingContextId?: string | null;
35
+ /** Disables every row while a choice is in flight. */
36
+ isLoading?: boolean;
37
+ /**
38
+ * This origin holds no session. A row then reads "Continue as @handle" and
39
+ * never as the current account: the device can list an identity as active
40
+ * while nobody is signed in HERE.
41
+ */
42
+ signedOut?: boolean;
43
+ }
44
+
45
+ export const OxyAccountPicker: React.FC<OxyAccountPickerProps> = ({
46
+ principals,
47
+ appName,
48
+ onSelectContext,
49
+ onUseAnother,
50
+ pendingContextId = null,
51
+ isLoading = false,
52
+ signedOut = false,
53
+ }) => {
54
+ const theme = useTheme();
55
+ const { t } = useI18n();
56
+ // Whose route a row is only needs naming once someone holds more than one
57
+ // account here — the same rule the account menu's group headers follow.
58
+ const namesTheOperator = showsPrincipalHeaders(principals);
59
+
60
+ return (
61
+ <OxyAuthScreen>
62
+ <OxyAuthScreenHeader
63
+ title={t('signin.chooser.title')}
64
+ description={appName ? t('signin.chooser.subtitleToApp', { app: appName }) : t('signin.chooser.subtitle')}
65
+ />
66
+ <View style={authChooserStyles.rows}>
67
+ {principals.flatMap((principal) =>
68
+ principal.contexts.map((context) => (
69
+ <AccountRow
70
+ key={context.contextId}
71
+ context={context}
72
+ operatedBy={
73
+ namesTheOperator && context.isDelegated
74
+ ? t('accountSwitcher.context.operatedBy', { name: principal.displayName })
75
+ : null
76
+ }
77
+ continueAsLabel={
78
+ signedOut
79
+ ? t('signin.chooser.continueAs', {
80
+ name: context.handle ? `@${context.handle}` : context.displayName,
81
+ })
82
+ : null
83
+ }
84
+ theme={theme}
85
+ activating={pendingContextId === context.contextId}
86
+ disabled={isLoading}
87
+ onPress={() => onSelectContext(context)}
88
+ />
89
+ )),
90
+ )}
91
+ <Pressable
92
+ onPress={onUseAnother}
93
+ disabled={isLoading}
94
+ accessibilityRole="button"
95
+ accessibilityLabel={t('signin.chooser.useAnother')}
96
+ style={[
97
+ authChooserStyles.accountRow,
98
+ { borderColor: theme.colors.border, backgroundColor: theme.colors.card },
99
+ isLoading ? authChooserStyles.rowDisabled : null,
100
+ ]}
101
+ testID="use-another-account"
102
+ >
103
+ <View style={[styles.addGlyph, { backgroundColor: theme.colors.backgroundSecondary }]}>
104
+ <RiUserAddLine size="md" fill={theme.colors.textSecondary} />
105
+ </View>
106
+ <Text style={[authChooserStyles.rowName, styles.addLabel, { color: theme.colors.text }]}>
107
+ {t('signin.chooser.useAnother')}
108
+ </Text>
109
+ <RiArrowRightSLine size="md" fill={theme.colors.textSecondary} />
110
+ </Pressable>
111
+ </View>
112
+ <OxyAuthTerms />
113
+ </OxyAuthScreen>
114
+ );
115
+ };
116
+
117
+ const styles = StyleSheet.create({
118
+ // Matches `AccountRow`'s 40px avatar plus its 2px ring and 1px gap.
119
+ addGlyph: {
120
+ width: 46,
121
+ height: 46,
122
+ borderRadius: 23,
123
+ alignItems: 'center',
124
+ justifyContent: 'center',
125
+ },
126
+ addLabel: {
127
+ flex: 1,
128
+ },
129
+ });
@@ -0,0 +1,123 @@
1
+ /**
2
+ * The shell every Oxy sign-in screen shares — the in-app account dialog and
3
+ * every page of the auth.oxy.so IdP render these, so the two cannot drift:
4
+ *
5
+ * header the Oxy mark (56), then the title (48/800, tight) and a 18px
6
+ * description, 8 apart
7
+ * screen blocks 24 apart, at most 448 wide
8
+ * split from `md`, Bloom `AuthCard`'s split base — max 880, radius 24,
9
+ * 1px border, two equal columns, the right one on the secondary
10
+ * surface; below `md` the right column is dropped, not stacked
11
+ * loading an indeterminate spinner holding the screen's height
12
+ * terms one centred caption linking the Terms of Service and Privacy Policy
13
+ *
14
+ * Layout is NativeWind `className` (breakpoints included). Type stays on
15
+ * Bloom `Text`'s own ramp through `style` — a `className` there drops its
16
+ * default family — and colours come from the Bloom theme.
17
+ */
18
+
19
+ import type React from 'react';
20
+ import { ActivityIndicator, Linking, Text as RNText } from 'react-native';
21
+ import { View } from 'react-native-css/components';
22
+ import { useTheme } from '@oxy.so/bloom/theme';
23
+ import { Text } from '@oxy.so/bloom/typography';
24
+ import { useI18n } from '../../hooks/useI18n';
25
+ import { LogoIcon } from '../logo/LogoIcon';
26
+
27
+ const LOGO_HEIGHT = 56;
28
+ const TERMS_URL = 'https://oxy.so/company/transparency/policies/terms-of-service';
29
+ const PRIVACY_URL = 'https://oxy.so/company/transparency/policies/privacy';
30
+
31
+ const TITLE = { fontSize: 48, lineHeight: 48, fontWeight: '800', letterSpacing: -1.2 } as const;
32
+ const DESCRIPTION = { fontSize: 18, lineHeight: 28 } as const;
33
+ const TERMS = { fontSize: 14, lineHeight: 20, textAlign: 'center', paddingHorizontal: 24 } as const;
34
+
35
+ export interface OxyAuthScreenHeaderProps {
36
+ title: string;
37
+ description?: React.ReactNode;
38
+ }
39
+
40
+ /** The Oxy mark over the screen's title and description. */
41
+ export const OxyAuthScreenHeader: React.FC<OxyAuthScreenHeaderProps> = ({ title, description }) => {
42
+ const theme = useTheme();
43
+ return (
44
+ <View className="gap-6">
45
+ <LogoIcon height={LOGO_HEIGHT} />
46
+ <View className="max-w-[90%] gap-2">
47
+ <Text accessibilityRole="header" style={[TITLE, { color: theme.colors.text }]}>
48
+ {title}
49
+ </Text>
50
+ {description != null && description !== '' ? (
51
+ typeof description === 'string' ? (
52
+ <Text style={[DESCRIPTION, { color: theme.colors.textSecondary }]}>
53
+ {description}
54
+ </Text>
55
+ ) : (
56
+ description
57
+ )
58
+ ) : null}
59
+ </View>
60
+ </View>
61
+ );
62
+ };
63
+
64
+ /** A sign-in screen's column: its blocks 24 apart. `className` extends it (the split's form column). */
65
+ export const OxyAuthScreen: React.FC<{ children: React.ReactNode; className?: string }> = ({ children, className }) => (
66
+ <View className={`w-full max-w-[448px] self-center gap-6 ${className ?? ''}`}>{children}</View>
67
+ );
68
+
69
+ /** The split card: `children` on the left and, from `md`, `aside` on the right. */
70
+ export const OxyAuthSplit: React.FC<{ children: React.ReactNode; aside: React.ReactNode }> = ({ children, aside }) => {
71
+ const theme = useTheme();
72
+ return (
73
+ <View
74
+ className="w-full self-center md:max-w-[880px] md:flex-row md:rounded-3xl md:border md:border-border md:bg-card md:overflow-hidden"
75
+ >
76
+ {/* Padding on an inner box: a padded flex item cannot shrink its base
77
+ size below its padding, which breaks the two equal tracks. */}
78
+ <View className="md:flex-1 md:basis-0 md:min-w-0">
79
+ <View className="md:p-8">{children}</View>
80
+ </View>
81
+ <View
82
+ className="hidden md:flex md:flex-1 md:basis-0 md:min-w-0 items-center justify-center overflow-hidden p-8"
83
+ style={{ backgroundColor: theme.colors.backgroundSecondary }}
84
+ >
85
+ {aside}
86
+ </View>
87
+ </View>
88
+ );
89
+ };
90
+
91
+ /**
92
+ * The screen while there is nothing to show yet. React Native's own indicator:
93
+ * `@oxy.so/bloom/loading` can tree-shake to `undefined` in a rolldown-vite
94
+ * production bundle when co-imported with `@oxy.so/bloom/button`.
95
+ */
96
+ export const OxyAuthLoading: React.FC = () => {
97
+ const theme = useTheme();
98
+ return (
99
+ <View className="min-h-[300px] items-center justify-center">
100
+ <ActivityIndicator size="large" color={theme.colors.primary} />
101
+ </View>
102
+ );
103
+ };
104
+
105
+ /** "By continuing, you agree to our Terms of Service and Privacy Policy." */
106
+ export const OxyAuthTerms: React.FC = () => {
107
+ const theme = useTheme();
108
+ const { t } = useI18n();
109
+ const link = { color: theme.colors.text, textDecorationLine: 'underline' as const };
110
+ return (
111
+ <Text style={[TERMS, { color: theme.colors.textSecondary }]}>
112
+ {t('signin.terms.before')}{' '}
113
+ <RNText accessibilityRole="link" style={link} onPress={() => void Linking.openURL(TERMS_URL)}>
114
+ {t('signin.terms.termsLink')}
115
+ </RNText>{' '}
116
+ {t('signin.terms.and')}{' '}
117
+ <RNText accessibilityRole="link" style={link} onPress={() => void Linking.openURL(PRIVACY_URL)}>
118
+ {t('signin.terms.privacyLink')}
119
+ </RNText>
120
+ .
121
+ </Text>
122
+ );
123
+ };
@@ -0,0 +1,392 @@
1
+ /**
2
+ * THE Oxy sign-in screen. The account dialog every Oxy app opens and the
3
+ * auth.oxy.so page render this one component; only where it is mounted
4
+ * differs (`host`).
5
+ *
6
+ * picker a returning device: "Choose an account", then "Use another account"
7
+ * entry the header, the Commons way in, and the way in for someone with no
8
+ * account. On auth.oxy.so (`page`) also the username with its
9
+ * Continue — a username-first passkey sign-in, which takes a
10
+ * platform passkey AND a hardware security key with no resident
11
+ * credential (a U2F key such as a Titan) — and "or continue with" the
12
+ * discoverable passkey. From `md` that page is Bloom `AuthCard`'s
13
+ * split card, with the embedded QR over its photo carousel in the
14
+ * right column; below `md` it is "Continue with Oxy" at the top.
15
+ * In an app's dialog on the web, "Continue with Oxy" opens that page
16
+ * in a window over the app, like "Sign in with Google": the browser's
17
+ * session lives on auth.oxy.so, so every Oxy app shares it. On
18
+ * native it is "Continue with Oxy" ("Get Commons" without Commons).
19
+ *
20
+ * `signInMethods.ts` owns which blocks a platform gets.
21
+ */
22
+
23
+ import type React from 'react';
24
+ import { useCallback, useEffect, useState } from 'react';
25
+ import { Linking, Platform, Text as RNText, StyleSheet, View } from 'react-native';
26
+ import { View as CssView } from 'react-native-css/components';
27
+ import { AuthMediaCarousel } from '@oxy.so/bloom/auth-card';
28
+ import { Button } from '@oxy.so/bloom/button';
29
+ import { Divider } from '@oxy.so/bloom/divider';
30
+ import { RiKey2Line } from '@oxy.so/bloom/icons/RiKey2Line';
31
+ import { RiQrCodeLine } from '@oxy.so/bloom/icons/RiQrCodeLine';
32
+ import { useTheme } from '@oxy.so/bloom/theme';
33
+ import { TextField, TextFieldHint, TextFieldInput, TextFieldLabel } from '@oxy.so/bloom/text-field';
34
+ import { toast } from '@oxy.so/bloom/toast';
35
+ import { Text } from '@oxy.so/bloom/typography';
36
+ import type { SwitcherContextRow } from '@oxy.so/core';
37
+ import { useQueryClient } from '@tanstack/react-query';
38
+ import { useOxy } from '../../context/OxyContext';
39
+ import { useAccountDialogSnapshot } from '../../hooks/accountDialogSnapshot';
40
+ import { useDeviceSwitcher } from '../../hooks/useDeviceSwitcher';
41
+ import { useI18n } from '../../hooks/useI18n';
42
+ import { getCommonsAcquisitionUrl } from '../../utils/commonsStoreLinks';
43
+ import { isWebBrowser } from '../../utils/isWebBrowser';
44
+ import { SubtleLink } from '../authChooser/primitives';
45
+ import { SIGN_IN_SLIDES } from './artwork';
46
+ import { InlineCommonsQr } from './InlineCommonsQr';
47
+ import { OxyAccountPicker } from './OxyAccountPicker';
48
+ import { OxyAuthScreen, OxyAuthScreenHeader, OxyAuthSplit, OxyAuthTerms } from './OxyAuthScreen';
49
+ import { RATE_LIMIT_SECONDS, describePasskeyError, isRateLimited } from './passkeyError';
50
+ import { resolveSignInMethods } from './signInMethods';
51
+
52
+ export interface OxySignInPanelProps {
53
+ /** This screen signed the origin in. */
54
+ onSignedIn: () => void;
55
+ /** "New to Oxy? Create one". */
56
+ onCreateAccount: () => void;
57
+ /** "Lost your passkey? Recover your account" — auth.oxy.so's page only. */
58
+ onRecover?: () => void;
59
+ /** A handle to pre-fill, skipping the picker (a re-authentication). */
60
+ loginHint?: string;
61
+ /** The app being continued to, when there is one. */
62
+ appName?: string | null;
63
+ /**
64
+ * `dialog` — inside the account dialog, which the controller closes itself
65
+ * once a request it runs signs in, and where a request shows in place.
66
+ * `page` — a page of its own (auth.oxy.so): a request opens the dialog to
67
+ * show it, and its completion is reported through `onSignedIn` too.
68
+ */
69
+ host?: 'dialog' | 'page';
70
+ }
71
+
72
+ export const OxySignInPanel: React.FC<OxySignInPanelProps> = ({
73
+ onSignedIn,
74
+ onCreateAccount,
75
+ onRecover,
76
+ loginHint,
77
+ appName = null,
78
+ host = 'page',
79
+ }) => {
80
+ const theme = useTheme();
81
+ const { t } = useI18n();
82
+ const queryClient = useQueryClient();
83
+ const { accountDialogController: controller, openAccountDialog, signInWithPasskey, continueOnAuth } = useOxy();
84
+ const snapshot = useAccountDialogSnapshot(controller);
85
+ const { principals, activeContext } = useDeviceSwitcher();
86
+
87
+ const methods = resolveSignInMethods({
88
+ web: isWebBrowser(),
89
+ host,
90
+ commonsAvailability: snapshot.commonsAvailability,
91
+ });
92
+
93
+ const [showForm, setShowForm] = useState(Boolean(loginHint));
94
+ const [identifier, setIdentifier] = useState(loginHint ?? '');
95
+ const [pending, setPending] = useState(false);
96
+ const [error, setError] = useState<string | null>(null);
97
+ const [rateLimitSeconds, setRateLimitSeconds] = useState(0);
98
+ const blocked = pending || rateLimitSeconds > 0;
99
+
100
+ // The countdown after a 429: one tick a second until the person may retry.
101
+ useEffect(() => {
102
+ if (rateLimitSeconds <= 0) return;
103
+ const timer = setTimeout(() => setRateLimitSeconds((seconds) => Math.max(0, seconds - 1)), 1000);
104
+ return () => clearTimeout(timer);
105
+ }, [rateLimitSeconds]);
106
+
107
+ // On a page, a request the controller runs (the embedded QR, or one shown in
108
+ // the dialog opened over it) finishes the page's sign-in too. Only one that
109
+ // STARTED here: a completion already on the controller is somebody else's.
110
+ const [mountedAttempt] = useState(snapshot.signIn.attempt);
111
+ const completedHere = snapshot.signIn.phase === 'completed' && snapshot.signIn.attempt !== mountedAttempt;
112
+ useEffect(() => {
113
+ if (host === 'page' && completedHere) onSignedIn();
114
+ }, [host, completedHere, onSignedIn]);
115
+
116
+ /** Show the request a controller call just started — the dialog is where it lives. */
117
+ const showRequest = useCallback(() => {
118
+ if (host === 'page') openAccountDialog('qr');
119
+ }, [host, openAccountDialog]);
120
+
121
+ // These open a window or leave the page, so they run straight from the
122
+ // press, before any await.
123
+ const continueWithOxy = () => {
124
+ void controller?.signInWithOxy();
125
+ showRequest();
126
+ };
127
+ const signInOnOxy = () => {
128
+ void continueOnAuth('signin').then((result) => {
129
+ if (result.status === 'signed-in') onSignedIn();
130
+ else if (result.status === 'failed') toast.error(t('signin.errors.failed'));
131
+ });
132
+ };
133
+ const useAnotherDevice = () => {
134
+ void controller?.showQr();
135
+ showRequest();
136
+ };
137
+ const getCommons = () => {
138
+ Promise.resolve()
139
+ .then(() => Linking.openURL(getCommonsAcquisitionUrl(Platform.OS)))
140
+ .catch(() => toast.error(t('accountSwitcher.linkOpenFailed')));
141
+ };
142
+
143
+ const runPasskey = async (username: string | undefined, failToast: string) => {
144
+ if (blocked) return;
145
+ setError(null);
146
+ setPending(true);
147
+ try {
148
+ await signInWithPasskey({ username });
149
+ onSignedIn();
150
+ } catch (err) {
151
+ if (isRateLimited(err)) {
152
+ setRateLimitSeconds(RATE_LIMIT_SECONDS);
153
+ } else {
154
+ const message = describePasskeyError(err, t);
155
+ setError(message);
156
+ toast.error(failToast, { description: message });
157
+ }
158
+ } finally {
159
+ setPending(false);
160
+ }
161
+ };
162
+ const submitUsername = () => {
163
+ const username = identifier.trim();
164
+ if (username) void runPasskey(username, t('signin.errors.failed'));
165
+ else setError(t('signin.username.required'));
166
+ };
167
+
168
+ // A returning device starts at WHO. Not while adding an account from inside
169
+ // a signed-in app: the rows are the accounts it would add.
170
+ const pickerAllowed = host === 'dialog' ? !snapshot.hasSession : activeContext !== null;
171
+ const reauthenticate = (context: SwitcherContextRow) => {
172
+ setIdentifier(context.handle ?? '');
173
+ setShowForm(true);
174
+ };
175
+ const selectContext = async (context: SwitcherContextRow) => {
176
+ const outcome = await controller?.chooseContext(context.contextId).catch(() => 'failed' as const);
177
+ switch (outcome) {
178
+ case 'switched':
179
+ // Every account-scoped query now describes somebody else.
180
+ void queryClient.invalidateQueries();
181
+ onSignedIn();
182
+ return;
183
+ case 'current':
184
+ onSignedIn();
185
+ return;
186
+ case 'signing-in':
187
+ // The request for that account is running; it shows where requests do.
188
+ showRequest();
189
+ return;
190
+ case 'failed':
191
+ // The pair could not be activated as it stands: sign in as it explicitly.
192
+ if (methods.passkey && context.handle) reauthenticate(context);
193
+ else toast.error(t('accountSwitcher.toasts.activateFailed'));
194
+ return;
195
+ default:
196
+ return;
197
+ }
198
+ };
199
+
200
+ const showsPicker = pickerAllowed && !showForm && principals.length > 0;
201
+ // auth.oxy.so's page is the split card from `md`.
202
+ const splits = methods.commons === 'qr';
203
+
204
+ if (showsPicker) {
205
+ return (
206
+ <OxyAccountPicker
207
+ principals={principals}
208
+ appName={appName}
209
+ signedOut={!snapshot.hasSession}
210
+ pendingContextId={snapshot.activatingContextId}
211
+ isLoading={snapshot.activatingContextId !== null}
212
+ onSelectContext={(context) => void selectContext(context)}
213
+ onUseAnother={() => {
214
+ setIdentifier('');
215
+ setShowForm(true);
216
+ }}
217
+ />
218
+ );
219
+ }
220
+
221
+ const shownError = rateLimitSeconds > 0 ? t('signin.errors.rateLimited', { seconds: rateLimitSeconds }) : error;
222
+
223
+ const adding = host === 'dialog' && snapshot.hasSession;
224
+ const title = adding ? t('signin.addAccountTitle') : t('signin.title');
225
+ const description = adding
226
+ ? t('signin.addAccountSubtitle')
227
+ : appName
228
+ ? t('signin.subtitleToApp', { app: appName })
229
+ : t('signin.subtitle');
230
+ const noAccount = (
231
+ <Text style={[styles.note, styles.noAccount, { color: theme.colors.textSecondary }]}>
232
+ {t('signin.noAccount')}{' '}
233
+ <RNText
234
+ accessibilityRole="link"
235
+ onPress={onCreateAccount}
236
+ style={[styles.noAccountLink, { color: theme.colors.text }]}
237
+ testID="create-account-link"
238
+ >
239
+ {t('signin.createAccount')}
240
+ </RNText>
241
+ </Text>
242
+ );
243
+ // One solid action per screen: the username's Continue when there is one.
244
+ const commonsAppearance = methods.passkey ? 'outline' : 'solid';
245
+
246
+ const continueWithOxyButton = (
247
+ <Button
248
+ appearance={commonsAppearance}
249
+ tone={commonsAppearance === 'solid' ? 'action' : 'neutral'}
250
+ size="lg"
251
+ fullWidth
252
+ onPress={methods.commons === 'window' ? signInOnOxy : continueWithOxy}
253
+ testID="continue-with-oxy"
254
+ >
255
+ {t('accountSwitcher.continueWithOxy')}
256
+ </Button>
257
+ );
258
+
259
+ const form = (
260
+ <OxyAuthScreen className={splits ? 'md:max-w-none' : undefined}>
261
+ <OxyAuthScreenHeader title={title} description={description} />
262
+
263
+ {/* Below `md` this screen is the phone a QR would be scanned with. */}
264
+ {splits ? <CssView className="md:hidden">{continueWithOxyButton}</CssView> : null}
265
+
266
+ {methods.commons === 'continue' || methods.commons === 'window' ? continueWithOxyButton : null}
267
+ {methods.commons === 'get-commons' ? (
268
+ <View style={styles.stack}>
269
+ <Text style={[styles.note, { color: theme.colors.textSecondary }]}>{t('accountSwitcher.commonsNotInstalled')}</Text>
270
+ <Button appearance="solid" tone="action" size="lg" fullWidth onPress={getCommons} testID="get-commons-button">
271
+ {t('accountSwitcher.getCommons')}
272
+ </Button>
273
+ </View>
274
+ ) : null}
275
+
276
+ {methods.passkey ? (
277
+ <View style={styles.stack}>
278
+ <View style={styles.field}>
279
+ <TextFieldLabel nativeID="username-label">{t('signin.username.label')}</TextFieldLabel>
280
+ <TextField invalid={shownError !== null} disabled={blocked} radius={999} style={styles.input}>
281
+ <TextFieldInput
282
+ testID="username"
283
+ label={t('signin.username.label')}
284
+ value={identifier}
285
+ onValueChange={(value) => {
286
+ setIdentifier(value);
287
+ if (error) setError(null);
288
+ }}
289
+ placeholder={t('signin.username.placeholder')}
290
+ autoComplete="username"
291
+ autoCapitalize="none"
292
+ autoCorrect={false}
293
+ autoFocus={Platform.OS === 'web'}
294
+ returnKeyType="go"
295
+ onSubmitEditing={submitUsername}
296
+ aria-required
297
+ />
298
+ </TextField>
299
+ {shownError ? <TextFieldHint invalid>{shownError}</TextFieldHint> : null}
300
+ </View>
301
+ {noAccount}
302
+ <Button
303
+ appearance="solid"
304
+ tone="action"
305
+ size="lg"
306
+ fullWidth
307
+ loading={pending}
308
+ disabled={blocked}
309
+ onPress={submitUsername}
310
+ testID="username-continue"
311
+ >
312
+ {t('signin.actions.continue')}
313
+ </Button>
314
+ </View>
315
+ ) : null}
316
+
317
+ {/* The alternatives to the screen's primary way in, always under it. The
318
+ window an app opens on the web is where they all are. */}
319
+ {methods.commons === 'window' ? null : <Divider>{t('signin.orContinueWith')}</Divider>}
320
+
321
+ {methods.passkey ? (
322
+ <Button
323
+ appearance="outline"
324
+ tone="neutral"
325
+ size="lg"
326
+ fullWidth
327
+ leadingIcon={RiKey2Line}
328
+ disabled={blocked}
329
+ onPress={() => void runPasskey(undefined, t('signin.errors.failed'))}
330
+ testID="passkey-sign-in"
331
+ >
332
+ {t('signin.methods.passkey')}
333
+ </Button>
334
+ ) : methods.commons === 'window' ? null : (
335
+ <Button
336
+ appearance="outline"
337
+ tone="neutral"
338
+ size="lg"
339
+ fullWidth
340
+ leadingIcon={RiQrCodeLine}
341
+ onPress={useAnotherDevice}
342
+ testID="scan-qr"
343
+ >
344
+ {t('accountSwitcher.scanQr')}
345
+ </Button>
346
+ )}
347
+
348
+ {methods.passkey ? null : noAccount}
349
+ {onRecover ? (
350
+ <SubtleLink label={t('signin.recoverLink')} theme={theme} onPress={onRecover} testID="recover-link" />
351
+ ) : null}
352
+ <OxyAuthTerms />
353
+ </OxyAuthScreen>
354
+ );
355
+
356
+ if (!splits) return form;
357
+ return (
358
+ <OxyAuthSplit
359
+ aside={
360
+ <>
361
+ <AuthMediaCarousel slides={SIGN_IN_SLIDES} style={StyleSheet.absoluteFill} />
362
+ <InlineCommonsQr controller={controller} />
363
+ </>
364
+ }
365
+ >
366
+ {form}
367
+ </OxyAuthSplit>
368
+ );
369
+ };
370
+
371
+ const styles = StyleSheet.create({
372
+ stack: {
373
+ gap: 12,
374
+ },
375
+ field: {
376
+ gap: 6,
377
+ },
378
+ note: {
379
+ fontSize: 14,
380
+ lineHeight: 20,
381
+ textAlign: 'center',
382
+ },
383
+ noAccount: {
384
+ textAlign: 'left',
385
+ },
386
+ noAccountLink: {
387
+ textDecorationLine: 'underline',
388
+ },
389
+ input: {
390
+ height: 40,
391
+ },
392
+ });