@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,86 @@
1
+ /**
2
+ * Account creation in the account dialog.
3
+ *
4
+ * On the web the account is made on auth.oxy.so, in its window over the app
5
+ * (`onCreateOnWeb`), and this app is signed in as it. On native, Commons
6
+ * creates the identity: straight in when it is installed, "Get Commons"
7
+ * otherwise.
8
+ */
9
+
10
+ import type React from 'react';
11
+ import { useCallback } from 'react';
12
+ import { Linking, Platform } from 'react-native';
13
+ import { Button } from '@oxy.so/bloom/button';
14
+ import { RiKey2Line } from '@oxy.so/bloom/icons/RiKey2Line';
15
+ import { useTheme } from '@oxy.so/bloom/theme';
16
+ import { toast } from '@oxy.so/bloom/toast';
17
+ import { useOxy } from '../../context/OxyContext';
18
+ import { useAccountDialogSnapshot } from '../../hooks/accountDialogSnapshot';
19
+ import { useI18n } from '../../hooks/useI18n';
20
+ import { getCommonsAcquisitionUrl } from '../../utils/commonsStoreLinks';
21
+ import { isWebBrowser } from '../../utils/isWebBrowser';
22
+ import { SubtleLink } from '../authChooser/primitives';
23
+ import { OxyAuthScreen, OxyAuthScreenHeader, OxyAuthTerms } from './OxyAuthScreen';
24
+
25
+ /** Commons' own identity-creation deep link. */
26
+ const COMMONS_CREATE_IDENTITY_URL = 'oxycommons://create-identity';
27
+
28
+ export interface OxySignUpPanelProps {
29
+ /** "Already have an account? Sign in". */
30
+ onSignIn: () => void;
31
+ /** The web's one action: auth.oxy.so's sign-up, in its window. */
32
+ onCreateOnWeb: () => void;
33
+ }
34
+
35
+ export const OxySignUpPanel: React.FC<OxySignUpPanelProps> = ({ onSignIn, onCreateOnWeb }) => {
36
+ const theme = useTheme();
37
+ const { t } = useI18n();
38
+ const { accountDialogController: controller } = useOxy();
39
+ const snapshot = useAccountDialogSnapshot(controller);
40
+ const web = isWebBrowser();
41
+
42
+ const openExternal = useCallback(
43
+ (url: string) => {
44
+ Promise.resolve()
45
+ .then(() => Linking.openURL(url))
46
+ .catch(() => toast.error(t('accountSwitcher.linkOpenFailed')));
47
+ },
48
+ [t],
49
+ );
50
+
51
+ const commonsInstalled = snapshot.commonsAvailability === 'available';
52
+
53
+ return (
54
+ <OxyAuthScreen>
55
+ <OxyAuthScreenHeader title={t('signup.title')} description={web ? t('signup.webSubtitle') : t('signup.subtitle')} />
56
+ {web ? (
57
+ <Button
58
+ appearance="solid"
59
+ tone="action"
60
+ size="lg"
61
+ fullWidth
62
+ leadingIcon={RiKey2Line}
63
+ onPress={onCreateOnWeb}
64
+ testID="signup-open-identity"
65
+ >
66
+ {t('signup.createAccount')}
67
+ </Button>
68
+ ) : (
69
+ <Button
70
+ appearance="solid"
71
+ tone="action"
72
+ size="lg"
73
+ fullWidth
74
+ onPress={() =>
75
+ openExternal(commonsInstalled ? COMMONS_CREATE_IDENTITY_URL : getCommonsAcquisitionUrl(Platform.OS))
76
+ }
77
+ testID="signup-commons"
78
+ >
79
+ {commonsInstalled ? t('signup.createInCommons') : t('accountSwitcher.getCommons')}
80
+ </Button>
81
+ )}
82
+ <SubtleLink label={t('signup.backToSignInLink')} theme={theme} onPress={onSignIn} testID="back-to-sign-in" />
83
+ <OxyAuthTerms />
84
+ </OxyAuthScreen>
85
+ );
86
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The photos the sign-in split card's carousel turns through. Shipped with the
3
+ * SDK and imported like its icon fonts, so every host serves them from its own
4
+ * origin — nothing to allow in anyone's CSP.
5
+ */
6
+
7
+ import type { AuthMediaSlide } from '@oxy.so/bloom/auth-card';
8
+ import slide1 from '../../../assets/signIn/slide-1.jpg';
9
+ import slide2 from '../../../assets/signIn/slide-2.jpg';
10
+ import slide3 from '../../../assets/signIn/slide-3.jpg';
11
+ import slide4 from '../../../assets/signIn/slide-4.jpg';
12
+
13
+ export const SIGN_IN_SLIDES: AuthMediaSlide[] = [slide1, slide2, slide3, slide4].map((source) => ({ source }));
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The message for a failed passkey sign-in, and whether it was rate-limited.
3
+ *
4
+ * A dismissed or timed-out browser prompt rejects with a `NotAllowedError` /
5
+ * `AbortError` DOMException, often re-wrapped by `@simplewebauthn/browser` as a
6
+ * `WebAuthnError` whose `cause` is the original — so the cancellation shape is
7
+ * looked for along the cause chain, and reported calmly instead of as the raw
8
+ * "The operation either timed out or was not allowed…".
9
+ */
10
+
11
+ import type { Translate } from '../authChooser/types';
12
+
13
+ /** How long the surface waits after a 429 before it lets the person retry. */
14
+ export const RATE_LIMIT_SECONDS = 60;
15
+
16
+ function isCancellation(error: unknown): boolean {
17
+ let current: unknown = error;
18
+ for (let depth = 0; depth < 5 && current instanceof Error; depth += 1) {
19
+ if (current.name === 'NotAllowedError' || current.name === 'AbortError') return true;
20
+ // `@simplewebauthn/browser`'s stable code for an aborted ceremony.
21
+ if ((current as { code?: unknown }).code === 'ERROR_CEREMONY_ABORTED') return true;
22
+ current = (current as { cause?: unknown }).cause;
23
+ }
24
+ return false;
25
+ }
26
+
27
+ /** An HTTP status off a thrown SDK error (ApiError- or axios-shaped). */
28
+ function errorStatus(error: unknown): number | undefined {
29
+ return (
30
+ (error as { status?: number } | undefined)?.status ??
31
+ (error as { response?: { status?: number } } | undefined)?.response?.status
32
+ );
33
+ }
34
+
35
+ export function isRateLimited(error: unknown): boolean {
36
+ return errorStatus(error) === 429;
37
+ }
38
+
39
+ /** The inline message for a passkey ceremony that did not sign anyone in. */
40
+ export function describePasskeyError(error: unknown, t: Translate): string {
41
+ if (isCancellation(error)) return t('signin.errors.passkeyCancelled');
42
+ if (error instanceof Error && error.message.trim().length > 0) return error.message;
43
+ return t('signin.errors.passkeyFailed');
44
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Which sign-in methods a surface offers, from where it runs.
3
+ *
4
+ * One screen everywhere; only the transport behind each block changes:
5
+ *
6
+ * - auth.oxy.so (`page`) is where the web signs in: the embedded Commons QR
7
+ * (the split card's right column from `md`, "Continue with Oxy" below it),
8
+ * the username with its Continue, and the passkey — asserted right here,
9
+ * on the one origin every Oxy passkey belongs to;
10
+ * - an app's account dialog on the web (`dialog`) opens that screen in a
11
+ * window over the app ("Continue with Oxy"), like "Sign in with Google":
12
+ * the browser's session lives on auth.oxy.so, so every Oxy app shares it;
13
+ * - native signs in with Commons: "Continue with Oxy", or "Get Commons" on a
14
+ * device that has no Commons to continue with.
15
+ */
16
+
17
+ import type { CommonsAvailability } from '@oxy.so/core';
18
+
19
+ /**
20
+ * `qr` — auth.oxy.so: the embedded QR from `md`, "Continue with Oxy" below.
21
+ * `window` — an app on the web: "Continue with Oxy" opens auth.oxy.so's window.
22
+ * `continue` — native "Continue with Oxy": Oxy picks the route (shared
23
+ * keychain, Commons on this device, a push, or the QR view).
24
+ * `get-commons` — native, and Commons is not installed here.
25
+ */
26
+ export type CommonsEntry = 'qr' | 'window' | 'continue' | 'get-commons';
27
+
28
+ export interface SignInMethods {
29
+ commons: CommonsEntry;
30
+ /** The username and passkey block: only on auth.oxy.so. */
31
+ passkey: boolean;
32
+ }
33
+
34
+ export interface SignInSurfaceFacts {
35
+ /** Rendering in a browser (react-native-web), not a native app. */
36
+ web: boolean;
37
+ /** `page` is auth.oxy.so; `dialog` is an app's account dialog. */
38
+ host: 'dialog' | 'page';
39
+ /** The controller's native probe for an installed Commons. */
40
+ commonsAvailability: CommonsAvailability;
41
+ }
42
+
43
+ export function resolveSignInMethods(facts: SignInSurfaceFacts): SignInMethods {
44
+ if (facts.web) {
45
+ return facts.host === 'page' ? { commons: 'qr', passkey: true } : { commons: 'window', passkey: false };
46
+ }
47
+ return {
48
+ commons: facts.commonsAvailability === 'unavailable' ? 'get-commons' : 'continue',
49
+ passkey: false,
50
+ };
51
+ }
@@ -9,7 +9,7 @@ import {
9
9
  useState,
10
10
  } from 'react';
11
11
  import { Linking, Platform } from 'react-native';
12
- import { OxyServices, oxyClient } from '@oxy.so/core';
12
+ import { DeviceManager, OxyServices, oxyClient, type OxyAuthScreen } from '@oxy.so/core';
13
13
  import type {
14
14
  User,
15
15
  SessionLoginResponse,
@@ -31,7 +31,6 @@ import {
31
31
  notifyAccountDialogVisibility,
32
32
  } from '../navigation/accountDialogManager';
33
33
  import { redirectToAuthorize } from '../components/oauthNavigation';
34
- import { openPasskeyHubPopup } from '../components/passkeyHubPopup';
35
34
  import {
36
35
  startWebOAuthSignIn,
37
36
  type StartWebOAuthSignInOptions,
@@ -149,7 +148,6 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
149
148
  sessionMode = 'account',
150
149
  webAuthMode = 'popup',
151
150
  backgroundSession = false,
152
- deviceCredentialStorage = 'persistent',
153
151
  platformStorage,
154
152
  onAuthStateChange,
155
153
  onError,
@@ -170,17 +168,9 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
170
168
 
171
169
  // The device-first persisted auth-state store (per-origin device credential on
172
170
  // web; SecureStore session blob on native). Built ONCE per provider mount.
173
- //
174
- // `deviceCredentialStorage` is mount-time configuration for the same reason
175
- // `sessionMode` is: it decides where the durable credential lives, and letting
176
- // it change mid-flight would mean a session that started ephemeral could begin
177
- // writing one.
178
171
  const authStoreRef = useRef<AuthStateStore | null>(null);
179
172
  if (!authStoreRef.current) {
180
- authStoreRef.current = createPlatformAuthStateStore({
181
- sessionMode,
182
- storage: deviceCredentialStorage,
183
- });
173
+ authStoreRef.current = createPlatformAuthStateStore({ sessionMode });
184
174
  }
185
175
  const authStore = authStoreRef.current;
186
176
 
@@ -794,6 +784,20 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
794
784
  [webAuthMode, oxyServices, clientId, authorizeBaseUrl, isIdentityBound, user?.id],
795
785
  );
796
786
 
787
+ // On the web an Oxy app signs in and creates accounts in auth.oxy.so's
788
+ // window over the app, like "Sign in with Google": the passkey belongs to
789
+ // that origin, and the browser's session lives there, shared by every Oxy
790
+ // app. A blocked window falls back to the same page in this tab.
791
+ const continueOnAuth = useCallback(
792
+ (screen: OxyAuthScreen): Promise<WebOAuthSignInResult> =>
793
+ startWebOAuthSignInForContext({
794
+ redirectUri: authRedirectUri ?? globalThis.location?.origin ?? '',
795
+ transport: 'popup',
796
+ screen,
797
+ }),
798
+ [startWebOAuthSignInForContext, authRedirectUri],
799
+ );
800
+
797
801
  // ── Unified account dialog ─────────────────────────────────────────────────
798
802
  // The single account-chooser + sign-in surface. Built ONCE per provider mount
799
803
  // and bound to the live `oxyServices` + `sessionClient` + this provider's
@@ -863,11 +867,6 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
863
867
  // controller short-circuits, so `redirectToAuthorize` never runs for the
864
868
  // `oxycommons://` payload.
865
869
  canOpenApp: isWebBrowser() ? undefined : (url) => Linking.canOpenURL(url),
866
- // Web-only: lets `startPasskeyHubSignIn` open the auth.oxy.so passkey hub
867
- // popup (b2) for a non-Oxy origin. `undefined` on native — there is no
868
- // popup concept there, and off-origin passkey sign-in isn't reachable
869
- // (Commons owns the native flow).
870
- openPopup: isWebBrowser() ? openPasskeyHubPopup : undefined,
871
870
  // Which surface a sign-in starts from — a FACT only this consumer can
872
871
  // supply (headless core never touches a platform global). It decides
873
872
  // whether automatic delivery may take the same-device Commons deep link;
@@ -983,7 +982,9 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
983
982
  username: opts?.username,
984
983
  deviceId: persisted?.deviceId,
985
984
  deviceName: opts?.deviceName,
986
- deviceFingerprint: opts?.deviceFingerprint,
985
+ // The same shape every other sign-in path sends; the server only reads it
986
+ // to place a device that has no persisted id yet.
987
+ deviceFingerprint: opts?.deviceFingerprint ?? JSON.stringify(DeviceManager.getDeviceFingerprint()),
987
988
  });
988
989
  },
989
990
  [oxyServices, authStore, commitSession],
@@ -1284,6 +1285,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
1284
1285
  revokeSuspiciousSignIn,
1285
1286
  handleWebSession,
1286
1287
  startWebOAuthSignIn: startWebOAuthSignInForContext,
1288
+ continueOnAuth,
1287
1289
  requestOAuthConsent: requestOAuthConsentForContext,
1288
1290
  logout,
1289
1291
  logoutAll,
@@ -1341,6 +1343,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
1341
1343
  revokeSuspiciousSignIn,
1342
1344
  handleWebSession,
1343
1345
  startWebOAuthSignInForContext,
1346
+ continueOnAuth,
1344
1347
  requestOAuthConsentForContext,
1345
1348
  logout,
1346
1349
  logoutAll,
@@ -1,11 +1,8 @@
1
1
  import type { User } from '@oxy.so/core';
2
2
  import { logger } from '@oxy.so/core';
3
- import type { WebAuthMode } from '../../oauth/types';
4
3
  import {
5
4
  commitDeviceSetAndResolve,
6
- maybeSyncHubAfterCommit,
7
5
  type CommitDeviceSetAndResolveDeps,
8
- type MaybeSyncHubAfterCommitDeps,
9
6
  } from '../commitSessionFlow';
10
7
 
11
8
  // A resolved promise chain (addCurrentAccount -> start -> syncFromClient) settles
@@ -206,92 +203,6 @@ describe('commitDeviceSetAndResolve — cold boot (activate: false)', () => {
206
203
  });
207
204
  });
208
205
 
209
- /**
210
- * Post-sign-in hub sync is a FULL-PAGE redirect to auth.oxy.so. It runs from the
211
- * ONE commit funnel, so gating it here gates every commit path at once —
212
- * `webAuthMode: 'popup'` must never bounce the tab, whichever path signed the
213
- * user in (#691 phase 7).
214
- */
215
- describe('maybeSyncHubAfterCommit — webAuthMode transport gate (#691 phase 7)', () => {
216
- const buildHubDeps = (
217
- overrides: Partial<MaybeSyncHubAfterCommitDeps> = {},
218
- ): MaybeSyncHubAfterCommitDeps => ({
219
- activate: true,
220
- hubSyncRequested: true,
221
- hubSyncEnabled: true,
222
- webAuthMode: 'redirect',
223
- syncHub: jest.fn(async () => true),
224
- ...overrides,
225
- });
226
-
227
- it("redirect mode: syncs the hub after a deliberate sign-in (unchanged)", async () => {
228
- const deps = buildHubDeps();
229
-
230
- await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(true);
231
-
232
- expect(deps.syncHub).toHaveBeenCalledTimes(1);
233
- });
234
-
235
- it('popup mode: NEVER syncs the hub, even on an otherwise-eligible sign-in', async () => {
236
- const deps = buildHubDeps({ webAuthMode: 'popup' });
237
-
238
- await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
239
-
240
- expect(deps.syncHub).not.toHaveBeenCalled();
241
- });
242
-
243
- it('popup mode: no commit path can opt back in', async () => {
244
- // Every commit path differs only in `activate` / `hubSyncRequested`; the
245
- // transport gate outranks all of them.
246
- for (const activate of [true, false]) {
247
- for (const hubSyncRequested of [true, false]) {
248
- const deps = buildHubDeps({ webAuthMode: 'popup', activate, hubSyncRequested });
249
- await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
250
- expect(deps.syncHub).not.toHaveBeenCalled();
251
- }
252
- }
253
- });
254
-
255
- it.each(['popup', 'redirect'] as const)(
256
- 'never syncs on a cold-boot restore, in either mode (%s)',
257
- async (webAuthMode: WebAuthMode) => {
258
- const deps = buildHubDeps({ webAuthMode, activate: false });
259
-
260
- await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
261
-
262
- expect(deps.syncHub).not.toHaveBeenCalled();
263
- },
264
- );
265
-
266
- it('redirect mode: honours the per-commit opt-out (account switch / popup OAuth lanes)', async () => {
267
- const deps = buildHubDeps({ hubSyncRequested: false });
268
-
269
- await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
270
-
271
- expect(deps.syncHub).not.toHaveBeenCalled();
272
- });
273
-
274
- it('redirect mode: honours the provider-level hubSync opt-out', async () => {
275
- const deps = buildHubDeps({ hubSyncEnabled: false });
276
-
277
- await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
278
-
279
- expect(deps.syncHub).not.toHaveBeenCalled();
280
- });
281
-
282
- it('redirect mode: a failing hub sync is non-fatal and never rejects', async () => {
283
- const deps = buildHubDeps({
284
- syncHub: jest.fn(async () => {
285
- throw new Error('hub ticket failed');
286
- }),
287
- });
288
-
289
- await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
290
-
291
- expect(deps.syncHub).toHaveBeenCalledTimes(1);
292
- });
293
- });
294
-
295
206
  describe('commitDeviceSetAndResolve — deliberate sign-in (activate: true)', () => {
296
207
  it('BLOCKS on the device-set reconcile before resolving auth (unchanged ordering)', async () => {
297
208
  const order: string[] = [];
@@ -1,8 +1,5 @@
1
1
  import type { User } from '@oxy.so/core';
2
2
  import { logger as loggerUtil } from '@oxy.so/core';
3
- import { allowsAutomaticIdpRedirect } from '../oauth/legacyRedirectLanes';
4
- import type { WebAuthMode } from '../oauth/types';
5
- import { isWebBrowser } from '../utils/isWebBrowser';
6
3
  import { isUnauthorizedStatus } from './oxyContextHelpers';
7
4
 
8
5
  const LOG_CONTEXT = { component: 'OxyContext', method: 'commitSession' } as const;
@@ -133,61 +130,3 @@ export async function commitDeviceSetAndResolve(
133
130
  await hydrateAndResolve();
134
131
  void reconcileDeviceSet().catch(logReconcileError);
135
132
  }
136
-
137
- export interface MaybeSyncHubAfterCommitDeps {
138
- /** Deliberate sign-in (`true`) vs. a cold-boot / background commit (`false`). */
139
- activate: boolean;
140
- /** Per-commit opt-in — `commitSession`'s `options.hubSync`. */
141
- hubSyncRequested: boolean;
142
- /** Provider-level opt-out — `OxyProviderProps.hubSync`. */
143
- hubSyncEnabled: boolean;
144
- /**
145
- * The provider's web sign-in transport — `OxyProviderProps.webAuthMode`.
146
- * A first-class input: `'popup'` forbids the redirect outright.
147
- */
148
- webAuthMode: WebAuthMode;
149
- /**
150
- * Starts the full-page hop to `auth.oxy.so/sync`; resolves `true` when the
151
- * navigation was actually started.
152
- */
153
- syncHub: () => Promise<boolean>;
154
- }
155
-
156
- /**
157
- * Post-sign-in hub sync: plant this device's credential on the IdP hub so OTHER
158
- * official origins can silently restore a session on their next cold boot.
159
- *
160
- * The tail of the ONE commit funnel (`commitSession`), extracted so every gate
161
- * on this legacy lane lives — and is tested — in one place. Returns whether the
162
- * full-page redirect was started; a failure is non-fatal and never propagates
163
- * (the sign-in itself already succeeded).
164
- *
165
- * Four gates, all of which must pass:
166
- * 1. `activate` — only a deliberate sign-in syncs; a cold-boot restore never does.
167
- * 2. `hubSyncRequested` — the in-place lanes (account switch, popup OAuth) opt out.
168
- * 3. `hubSyncEnabled` — the provider-level `hubSync` prop.
169
- * 4. `allowsAutomaticIdpRedirect(webAuthMode)` — hub sync REPLACES the document
170
- * with `auth.oxy.so`, so `webAuthMode: 'popup'` forbids it: a redirect that
171
- * bounces the tab defeats the entire point of the mode, no matter which
172
- * commit path produced the session (issue #691, "Cold boot and cross-domain
173
- * behavior"). Redirect mode — the default and the compatibility path — is
174
- * unchanged, and this whole function disappears with it in phase 7b.
175
- */
176
- export async function maybeSyncHubAfterCommit(
177
- deps: MaybeSyncHubAfterCommitDeps,
178
- ): Promise<boolean> {
179
- const { activate, hubSyncRequested, hubSyncEnabled, webAuthMode, syncHub } = deps;
180
-
181
- if (!activate || !hubSyncRequested || !hubSyncEnabled) return false;
182
- if (!allowsAutomaticIdpRedirect(webAuthMode)) return false;
183
- if (!isWebBrowser()) return false;
184
-
185
- try {
186
- return await syncHub();
187
- } catch (hubError) {
188
- if (__DEV__) {
189
- loggerUtil.debug('Hub sync after sign-in failed (non-fatal)', LOG_CONTEXT, hubError);
190
- }
191
- return false;
192
- }
193
- }
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { OxyServices, User, SessionLoginResponse, AccountNode, CreateAccountInput, ClientSession, AccountDialogController, AccountDialogView, ApiError, SessionClient, SessionMode } from '@oxy.so/core';
2
+ import type { OxyServices, User, SessionLoginResponse, AccountNode, CreateAccountInput, ClientSession, AccountDialogController, AccountDialogView, ApiError, SessionClient, SessionMode, OxyAuthScreen } from '@oxy.so/core';
3
3
  import type { UseFollowHook } from '../hooks/useFollow.types';
4
4
  import type { useLanguageManagement } from '../hooks/useLanguageManagement';
5
5
  import type { RouteName } from '../navigation/routes';
@@ -124,6 +124,14 @@ export interface OxyContextState {
124
124
  */
125
125
  startWebOAuthSignIn: (options: StartWebOAuthSignInOptions) => Promise<WebOAuthSignInResult>;
126
126
 
127
+ /**
128
+ * Sign in (`signin`), create an account (`signup`) or recover one
129
+ * (`recover`) in auth.oxy.so's window over the app, where the browser's
130
+ * shared Oxy session lives. Web only; call it from the press, so the window
131
+ * opens with the gesture.
132
+ */
133
+ continueOnAuth: (screen: OxyAuthScreen) => Promise<WebOAuthSignInResult>;
134
+
127
135
  /**
128
136
  * Ask the already-authenticated user for explicit OAuth consent to exact
129
137
  * application scopes. Must be called from a user gesture. Works on web and
@@ -219,14 +227,6 @@ export interface OxyRuntimeProviderProps {
219
227
  * @default false
220
228
  */
221
229
  backgroundSession?: boolean;
222
- /**
223
- * Whether this origin/app persists the durable device credential at all. See
224
- * `OxyProviderProps.deviceCredentialStorage` for the full rule and the one
225
- * caller of `'ephemeral'`.
226
- *
227
- * @default 'persistent'
228
- */
229
- deviceCredentialStorage?: 'persistent' | 'ephemeral';
230
230
  onAuthStateChange?: (user: User | null) => void;
231
231
  onError?: (error: ApiError) => void;
232
232
  /** Storage instance owned by the public provider; internal composition seam. */
@@ -1,4 +1,5 @@
1
- import type { AccountDialogSnapshot } from '@oxy.so/core';
1
+ import { useCallback, useSyncExternalStore } from 'react';
2
+ import type { AccountDialogController, AccountDialogSnapshot } from '@oxy.so/core';
2
3
 
3
4
  /**
4
5
  * The snapshot `useSyncExternalStore` reads before a controller exists.
@@ -36,6 +37,24 @@ export const EMPTY_ACCOUNT_DIALOG_SNAPSHOT: AccountDialogSnapshot = {
36
37
  openedAt: null,
37
38
  progress: 'idle',
38
39
  attempt: 0,
40
+ inline: false,
39
41
  },
40
42
  commonsAvailability: 'unknown',
41
43
  };
44
+
45
+ /**
46
+ * Bind a surface to `controller`'s snapshot (the inert one while there is no
47
+ * controller). `getSnapshot` returns a stable reference between changes, so
48
+ * it is `useSyncExternalStore`-safe.
49
+ */
50
+ export function useAccountDialogSnapshot(controller: AccountDialogController | null): AccountDialogSnapshot {
51
+ const subscribe = useCallback(
52
+ (listener: () => void) => (controller ? controller.subscribe(listener) : () => undefined),
53
+ [controller],
54
+ );
55
+ const getSnapshot = useCallback(
56
+ () => (controller ? controller.getSnapshot() : EMPTY_ACCOUNT_DIALOG_SNAPSHOT),
57
+ [controller],
58
+ );
59
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
60
+ }
@@ -1,4 +1,4 @@
1
- import { useCallback, useMemo, useSyncExternalStore } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import {
3
3
  buildSwitcherRows,
4
4
  projectDevicePrincipals,
@@ -7,7 +7,7 @@ import {
7
7
  } from '@oxy.so/core';
8
8
  import { useOxy } from '../context/OxyContext';
9
9
  import { useI18n } from './useI18n';
10
- import { EMPTY_ACCOUNT_DIALOG_SNAPSHOT } from './accountDialogSnapshot';
10
+ import { useAccountDialogSnapshot } from './accountDialogSnapshot';
11
11
 
12
12
  export interface UseDeviceSwitcherResult {
13
13
  /**
@@ -60,15 +60,7 @@ export function useDeviceSwitcher(): UseDeviceSwitcherResult {
60
60
  const { accountDialogController: controller, oxyServices } = useOxy();
61
61
  const { locale } = useI18n();
62
62
 
63
- const subscribe = useCallback(
64
- (listener: () => void) => (controller ? controller.subscribe(listener) : () => undefined),
65
- [controller],
66
- );
67
- const getSnapshot = useCallback(
68
- () => (controller ? controller.getSnapshot() : EMPTY_ACCOUNT_DIALOG_SNAPSHOT),
69
- [controller],
70
- );
71
- const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
63
+ const snapshot = useAccountDialogSnapshot(controller);
72
64
 
73
65
  // `directory` is a stable reference between reads (`SessionClient` holds the
74
66
  // one it applied), so this recomputes only when the device actually moved.
@@ -153,6 +153,27 @@ describe('startWebOAuthSignIn', () => {
153
153
  expect(openSpy).toHaveBeenCalledTimes(1);
154
154
  });
155
155
 
156
+ // An Oxy app's account dialog asks for the window whatever the provider's
157
+ // `webAuthMode`, and for the IdP screen the person lands on.
158
+ it('opens the window for `transport: popup` even in redirect mode, with its screen', async () => {
159
+ const context = makeContext({ mode: 'redirect' });
160
+ const popup = fakePopup();
161
+ const openSpy = jest.spyOn(window, 'open').mockReturnValue(popup as unknown as Window);
162
+
163
+ const pending = startWebOAuthSignIn(context, { redirectUri: REDIRECT_URI, transport: 'popup', screen: 'signup' });
164
+ const authorizeUrl = await waitForAuthorizeUrl(popup);
165
+ expect(authorizeUrl.searchParams.get('screen')).toBe('signup');
166
+ expect(authorizeUrl.searchParams.get('response_mode')).toBe('web_message');
167
+ dispatchFromPopup(
168
+ { type: OXY_OAUTH_CODE_MESSAGE_TYPE, code: 'code-1', state: authorizeUrl.searchParams.get('state') },
169
+ popup,
170
+ );
171
+
172
+ await expect(pending).resolves.toEqual({ status: 'signed-in' });
173
+ expect(openSpy).toHaveBeenCalledTimes(1);
174
+ expect(mockRedirect).not.toHaveBeenCalled();
175
+ });
176
+
156
177
  it('falls back to a full-page redirect when the popup was blocked', async () => {
157
178
  const context = makeContext();
158
179
 
@@ -14,7 +14,7 @@
14
14
  * remains the native lane and is untouched by this module.
15
15
  */
16
16
 
17
- import { logger, persistOAuthHandshake } from '@oxy.so/core';
17
+ import { logger, persistOAuthHandshake, type OxyAuthScreen } from '@oxy.so/core';
18
18
  import type { OxyServices } from '@oxy.so/core';
19
19
  import { redirectToAuthorize } from '../components/oauthNavigation';
20
20
  import { isWebBrowser } from '../utils/isWebBrowser';
@@ -64,6 +64,14 @@ export interface StartWebOAuthSignInOptions {
64
64
  popup?: OAuthPopupHandle | null;
65
65
  /** Requested scope; defaults to the SDK's standard sign-in scope. */
66
66
  scope?: string;
67
+ /**
68
+ * The transport for this press, whatever the provider's `webAuthMode`. An
69
+ * Oxy app's own account dialog asks for `popup`: auth.oxy.so's window over
70
+ * the app, where the browser's shared session lives.
71
+ */
72
+ transport?: WebAuthMode;
73
+ /** The IdP screen a person with no session there lands on. */
74
+ screen?: OxyAuthScreen;
67
75
  /** Popup timeout override (ms). */
68
76
  timeoutMs?: number;
69
77
  }
@@ -88,10 +96,10 @@ export async function startWebOAuthSignIn(
88
96
  // Claim the window BEFORE the first `await` below, so a caller that invoked us
89
97
  // straight from the click still has gesture attribution. An explicit `null`
90
98
  // means the caller already tried and was blocked.
91
- const popup =
92
- context.mode === 'popup' && options.popup === undefined ? openOAuthPopup() : options.popup ?? null;
99
+ const mode = options.transport ?? context.mode;
100
+ const popup = mode === 'popup' && options.popup === undefined ? openOAuthPopup() : options.popup ?? null;
93
101
 
94
- if (context.mode === 'redirect') {
102
+ if (mode === 'redirect') {
95
103
  closeOAuthPopup(popup);
96
104
  return startRedirectSignIn(context, options, 'redirect-mode');
97
105
  }
@@ -109,6 +117,7 @@ export async function startWebOAuthSignIn(
109
117
  authorizeBaseUrl: context.authorizeBaseUrl,
110
118
  scope: options.scope,
111
119
  responseMode: 'web_message',
120
+ ...(options.screen ? { screen: options.screen } : {}),
112
121
  });
113
122
 
114
123
  if (!navigateOAuthPopup(popup, prepared.authorizeUrl)) {
@@ -178,6 +187,7 @@ async function startRedirectSignIn(
178
187
  redirectUri: options.redirectUri,
179
188
  authorizeBaseUrl: context.authorizeBaseUrl,
180
189
  scope: options.scope,
190
+ ...(options.screen ? { screen: options.screen } : {}),
181
191
  });
182
192
 
183
193
  if (!persistOAuthHandshake(