@oxyhq/services 16.0.0 → 18.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 (278) hide show
  1. package/README.md +77 -98
  2. package/lib/commonjs/index.js +40 -51
  3. package/lib/commonjs/index.js.map +1 -1
  4. package/lib/commonjs/ui/client.js +0 -14
  5. package/lib/commonjs/ui/client.js.map +1 -1
  6. package/lib/commonjs/ui/components/OxyAccountDialog.js +742 -0
  7. package/lib/commonjs/ui/components/OxyAccountDialog.js.map +1 -0
  8. package/lib/commonjs/ui/components/OxyConsentScreen.js +461 -0
  9. package/lib/commonjs/ui/components/OxyConsentScreen.js.map +1 -0
  10. package/lib/commonjs/ui/components/OxyProvider.js +13 -6
  11. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  12. package/lib/commonjs/ui/components/OxySignInButton.js +180 -22
  13. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  14. package/lib/commonjs/ui/components/ProfileButton.js +25 -112
  15. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  16. package/lib/commonjs/ui/components/RequireOxyAuth.js +299 -0
  17. package/lib/commonjs/ui/components/RequireOxyAuth.js.map +1 -0
  18. package/lib/commonjs/ui/components/oauthNavigation.js +73 -0
  19. package/lib/commonjs/ui/components/oauthNavigation.js.map +1 -0
  20. package/lib/commonjs/ui/context/OxyContext.js +122 -4
  21. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  22. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +1 -1
  23. package/lib/commonjs/ui/hooks/useAuth.js +19 -30
  24. package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
  25. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +37 -267
  26. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -1
  27. package/lib/commonjs/ui/index.js +5 -40
  28. package/lib/commonjs/ui/index.js.map +1 -1
  29. package/lib/commonjs/ui/navigation/accountDialogManager.js +91 -0
  30. package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -0
  31. package/lib/commonjs/ui/navigation/routes.js +0 -2
  32. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  33. package/lib/commonjs/ui/screens/ManageAccountScreen.js +4 -3
  34. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  35. package/lib/commonjs/ui/session/createSessionClient.js +10 -2
  36. package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
  37. package/lib/module/index.js +19 -16
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/ui/client.js +1 -2
  40. package/lib/module/ui/client.js.map +1 -1
  41. package/lib/module/ui/components/OxyAccountDialog.js +739 -0
  42. package/lib/module/ui/components/OxyAccountDialog.js.map +1 -0
  43. package/lib/module/ui/components/OxyConsentScreen.js +454 -0
  44. package/lib/module/ui/components/OxyConsentScreen.js.map +1 -0
  45. package/lib/module/ui/components/OxyProvider.js +13 -6
  46. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  47. package/lib/module/ui/components/OxySignInButton.js +181 -22
  48. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  49. package/lib/module/ui/components/ProfileButton.js +26 -112
  50. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  51. package/lib/module/ui/components/RequireOxyAuth.js +294 -0
  52. package/lib/module/ui/components/RequireOxyAuth.js.map +1 -0
  53. package/lib/module/ui/components/oauthNavigation.js +70 -0
  54. package/lib/module/ui/components/oauthNavigation.js.map +1 -0
  55. package/lib/module/ui/context/OxyContext.js +123 -5
  56. package/lib/module/ui/context/OxyContext.js.map +1 -1
  57. package/lib/module/ui/hooks/mutations/useAccountMutations.js +1 -1
  58. package/lib/module/ui/hooks/useAuth.js +19 -30
  59. package/lib/module/ui/hooks/useAuth.js.map +1 -1
  60. package/lib/module/ui/hooks/useSwitchableAccounts.js +38 -267
  61. package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -1
  62. package/lib/module/ui/index.js +1 -5
  63. package/lib/module/ui/index.js.map +1 -1
  64. package/lib/module/ui/navigation/accountDialogManager.js +81 -0
  65. package/lib/module/ui/navigation/accountDialogManager.js.map +1 -0
  66. package/lib/module/ui/navigation/routes.js +0 -2
  67. package/lib/module/ui/navigation/routes.js.map +1 -1
  68. package/lib/module/ui/screens/ManageAccountScreen.js +4 -3
  69. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  70. package/lib/module/ui/session/createSessionClient.js +10 -2
  71. package/lib/module/ui/session/createSessionClient.js.map +1 -1
  72. package/lib/typescript/commonjs/index.d.ts +8 -12
  73. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  74. package/lib/typescript/commonjs/ui/client.d.ts +0 -4
  75. package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts +51 -0
  77. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts +45 -0
  79. package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts +2 -2
  81. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +56 -0
  83. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +11 -23
  85. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +55 -0
  87. package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts.map +1 -0
  88. package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts +36 -0
  89. package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +27 -1
  91. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  92. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  93. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts +1 -1
  94. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  95. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
  96. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +13 -152
  97. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/ui/index.d.ts +2 -5
  99. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +49 -0
  101. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
  103. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  104. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
  105. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  106. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +9 -2
  107. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/ui/types/navigation.d.ts +27 -0
  109. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  110. package/lib/typescript/module/index.d.ts +8 -12
  111. package/lib/typescript/module/index.d.ts.map +1 -1
  112. package/lib/typescript/module/ui/client.d.ts +0 -4
  113. package/lib/typescript/module/ui/client.d.ts.map +1 -1
  114. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts +51 -0
  115. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +1 -0
  116. package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts +45 -0
  117. package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts.map +1 -0
  118. package/lib/typescript/module/ui/components/OxyProvider.d.ts +2 -2
  119. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  120. package/lib/typescript/module/ui/components/OxySignInButton.d.ts +56 -0
  121. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  122. package/lib/typescript/module/ui/components/ProfileButton.d.ts +11 -23
  123. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
  124. package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +55 -0
  125. package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts.map +1 -0
  126. package/lib/typescript/module/ui/components/oauthNavigation.d.ts +36 -0
  127. package/lib/typescript/module/ui/components/oauthNavigation.d.ts.map +1 -0
  128. package/lib/typescript/module/ui/context/OxyContext.d.ts +27 -1
  129. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  130. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  131. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts +1 -1
  132. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  133. package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
  134. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +13 -152
  135. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
  136. package/lib/typescript/module/ui/index.d.ts +2 -5
  137. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  138. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +49 -0
  139. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -0
  140. package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
  141. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  142. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
  143. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  144. package/lib/typescript/module/ui/session/createSessionClient.d.ts +9 -2
  145. package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
  146. package/lib/typescript/module/ui/types/navigation.d.ts +27 -0
  147. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  148. package/package.json +4 -4
  149. package/src/index.ts +33 -27
  150. package/src/ui/client.ts +0 -4
  151. package/src/ui/components/OxyAccountDialog.tsx +735 -0
  152. package/src/ui/components/OxyConsentScreen.tsx +456 -0
  153. package/src/ui/components/OxyProvider.tsx +14 -6
  154. package/src/ui/components/OxySignInButton.tsx +227 -22
  155. package/src/ui/components/ProfileButton.tsx +23 -126
  156. package/src/ui/components/RequireOxyAuth.tsx +266 -0
  157. package/src/ui/components/__tests__/OxyConsentScreen.test.tsx +130 -0
  158. package/src/ui/components/oauthNavigation.ts +89 -0
  159. package/src/ui/context/OxyContext.tsx +176 -9
  160. package/src/ui/context/__tests__/OxyContext.coldBoot.test.tsx +165 -0
  161. package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
  162. package/src/ui/hooks/useAuth.ts +19 -31
  163. package/src/ui/hooks/useSwitchableAccounts.ts +42 -376
  164. package/src/ui/index.ts +2 -5
  165. package/src/ui/navigation/accountDialogManager.ts +84 -0
  166. package/src/ui/navigation/routes.ts +0 -4
  167. package/src/ui/screens/ManageAccountScreen.tsx +3 -2
  168. package/src/ui/session/createSessionClient.ts +9 -1
  169. package/src/ui/types/navigation.ts +27 -0
  170. package/lib/commonjs/ui/components/AccountMenu.js +0 -598
  171. package/lib/commonjs/ui/components/AccountMenu.js.map +0 -1
  172. package/lib/commonjs/ui/components/AccountMenuButton.js +0 -135
  173. package/lib/commonjs/ui/components/AccountMenuButton.js.map +0 -1
  174. package/lib/commonjs/ui/components/AccountSwitcher.js +0 -780
  175. package/lib/commonjs/ui/components/AccountSwitcher.js.map +0 -1
  176. package/lib/commonjs/ui/components/AnotherDeviceQR.js +0 -116
  177. package/lib/commonjs/ui/components/AnotherDeviceQR.js.map +0 -1
  178. package/lib/commonjs/ui/components/ProfileMenu.js +0 -518
  179. package/lib/commonjs/ui/components/ProfileMenu.js.map +0 -1
  180. package/lib/commonjs/ui/components/SignInAccountChooser.js +0 -189
  181. package/lib/commonjs/ui/components/SignInAccountChooser.js.map +0 -1
  182. package/lib/commonjs/ui/components/SignInModal.js +0 -600
  183. package/lib/commonjs/ui/components/SignInModal.js.map +0 -1
  184. package/lib/commonjs/ui/hooks/useOxyAuthSession.js +0 -501
  185. package/lib/commonjs/ui/hooks/useOxyAuthSession.js.map +0 -1
  186. package/lib/commonjs/ui/hooks/usePasswordSignIn.js +0 -170
  187. package/lib/commonjs/ui/hooks/usePasswordSignIn.js.map +0 -1
  188. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +0 -51
  189. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +0 -1
  190. package/lib/commonjs/ui/screens/OxyAuthScreen.js +0 -312
  191. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +0 -1
  192. package/lib/commonjs/utils/deviceFlowSignIn.js +0 -109
  193. package/lib/commonjs/utils/deviceFlowSignIn.js.map +0 -1
  194. package/lib/module/ui/components/AccountMenu.js +0 -593
  195. package/lib/module/ui/components/AccountMenu.js.map +0 -1
  196. package/lib/module/ui/components/AccountMenuButton.js +0 -130
  197. package/lib/module/ui/components/AccountMenuButton.js.map +0 -1
  198. package/lib/module/ui/components/AccountSwitcher.js +0 -774
  199. package/lib/module/ui/components/AccountSwitcher.js.map +0 -1
  200. package/lib/module/ui/components/AnotherDeviceQR.js +0 -110
  201. package/lib/module/ui/components/AnotherDeviceQR.js.map +0 -1
  202. package/lib/module/ui/components/ProfileMenu.js +0 -514
  203. package/lib/module/ui/components/ProfileMenu.js.map +0 -1
  204. package/lib/module/ui/components/SignInAccountChooser.js +0 -183
  205. package/lib/module/ui/components/SignInAccountChooser.js.map +0 -1
  206. package/lib/module/ui/components/SignInModal.js +0 -591
  207. package/lib/module/ui/components/SignInModal.js.map +0 -1
  208. package/lib/module/ui/hooks/useOxyAuthSession.js +0 -495
  209. package/lib/module/ui/hooks/useOxyAuthSession.js.map +0 -1
  210. package/lib/module/ui/hooks/usePasswordSignIn.js +0 -165
  211. package/lib/module/ui/hooks/usePasswordSignIn.js.map +0 -1
  212. package/lib/module/ui/screens/AccountSwitcherScreen.js +0 -48
  213. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +0 -1
  214. package/lib/module/ui/screens/OxyAuthScreen.js +0 -306
  215. package/lib/module/ui/screens/OxyAuthScreen.js.map +0 -1
  216. package/lib/module/utils/deviceFlowSignIn.js +0 -106
  217. package/lib/module/utils/deviceFlowSignIn.js.map +0 -1
  218. package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +0 -47
  219. package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +0 -1
  220. package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts +0 -26
  221. package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts.map +0 -1
  222. package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts +0 -46
  223. package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +0 -1
  224. package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts +0 -34
  225. package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts.map +0 -1
  226. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +0 -49
  227. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +0 -1
  228. package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts +0 -29
  229. package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts.map +0 -1
  230. package/lib/typescript/commonjs/ui/components/SignInModal.d.ts +0 -28
  231. package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +0 -1
  232. package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts +0 -105
  233. package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
  234. package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts +0 -31
  235. package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
  236. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts +0 -11
  237. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
  238. package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts +0 -22
  239. package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +0 -1
  240. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +0 -97
  241. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +0 -1
  242. package/lib/typescript/module/ui/components/AccountMenu.d.ts +0 -47
  243. package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +0 -1
  244. package/lib/typescript/module/ui/components/AccountMenuButton.d.ts +0 -26
  245. package/lib/typescript/module/ui/components/AccountMenuButton.d.ts.map +0 -1
  246. package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +0 -46
  247. package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +0 -1
  248. package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts +0 -34
  249. package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts.map +0 -1
  250. package/lib/typescript/module/ui/components/ProfileMenu.d.ts +0 -49
  251. package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +0 -1
  252. package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts +0 -29
  253. package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts.map +0 -1
  254. package/lib/typescript/module/ui/components/SignInModal.d.ts +0 -28
  255. package/lib/typescript/module/ui/components/SignInModal.d.ts.map +0 -1
  256. package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts +0 -105
  257. package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
  258. package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts +0 -31
  259. package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
  260. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts +0 -11
  261. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
  262. package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts +0 -22
  263. package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +0 -1
  264. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +0 -97
  265. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +0 -1
  266. package/src/ui/components/AccountMenu.tsx +0 -645
  267. package/src/ui/components/AccountMenuButton.tsx +0 -126
  268. package/src/ui/components/AccountSwitcher.tsx +0 -751
  269. package/src/ui/components/AnotherDeviceQR.tsx +0 -119
  270. package/src/ui/components/ProfileMenu.tsx +0 -564
  271. package/src/ui/components/SignInAccountChooser.tsx +0 -162
  272. package/src/ui/components/SignInModal.tsx +0 -530
  273. package/src/ui/hooks/useOxyAuthSession.ts +0 -635
  274. package/src/ui/hooks/usePasswordSignIn.ts +0 -207
  275. package/src/ui/screens/AccountSwitcherScreen.tsx +0 -43
  276. package/src/ui/screens/OxyAuthScreen.tsx +0 -324
  277. package/src/utils/__tests__/deviceFlowSignIn.test.ts +0 -231
  278. package/src/utils/deviceFlowSignIn.ts +0 -152
@@ -0,0 +1,456 @@
1
+ /**
2
+ * OxyConsentScreen — the unified OAuth authorize/consent surface for
3
+ * `@oxyhq/services`.
4
+ *
5
+ * A PURE, presentational React Native component: it renders the resolved
6
+ * requesting-application identity, the permissions (scopes) being requested,
7
+ * the account that will authorize the request, and the allow/deny affordances —
8
+ * and delegates every decision back through {@link OxyConsentScreenProps.onAllow}
9
+ * / {@link OxyConsentScreenProps.onDeny}. It performs NO data fetching and owns
10
+ * NO session state: the caller resolves the application + scopes + user (the IdP
11
+ * from `GET /auth/session/approve-info/:code`, Console from its own request) and
12
+ * drives the `busy` / `error` flags. This is the RN/Bloom port of the web
13
+ * `consent-card` (`packages/auth`), so the two consent surfaces stay in visual
14
+ * and behavioral lockstep.
15
+ *
16
+ * Theming is `useTheme()` + a `StyleSheet` (the same approach as
17
+ * {@link OxyAccountDialog}) so it renders correctly in EVERY consumer, including
18
+ * apps that do not use NativeWind. Copy is localized through {@link useI18n}
19
+ * under the `consent.*` keys.
20
+ */
21
+ import { useCallback } from 'react';
22
+ import { Linking, Pressable, ScrollView, StyleSheet, View } from 'react-native';
23
+ import { logger } from '@oxyhq/core';
24
+ import { Avatar } from '@oxyhq/bloom/avatar';
25
+ import { Button } from '@oxyhq/bloom/button';
26
+ import { Text } from '@oxyhq/bloom/typography';
27
+ import { useTheme } from '@oxyhq/bloom/theme';
28
+ import { useI18n } from '../hooks/useI18n';
29
+ import OxyLogo from './OxyLogo';
30
+
31
+ /** The requesting application, resolved by the caller (never user-supplied raw). */
32
+ export interface OxyConsentApplication {
33
+ /** Display name of the requesting application. */
34
+ name: string;
35
+ /** Application icon — a URL or bare file id passed straight to `<Avatar source>`. */
36
+ iconUrl?: string;
37
+ /** Public website of the application, shown as a link when present. */
38
+ websiteUrl?: string;
39
+ /** Privacy policy URL, shown as a link when present. */
40
+ privacyPolicyUrl?: string;
41
+ /** Terms of service URL, shown as a link when present. */
42
+ termsUrl?: string;
43
+ /** Human-readable publisher, used for the "Published by …" provenance line. */
44
+ developerName?: string;
45
+ /** True for first-party / official Oxy applications. */
46
+ isOfficial?: boolean;
47
+ }
48
+
49
+ /** The account that will authorize the request (the currently signed-in user). */
50
+ export interface OxyConsentUser {
51
+ /** Real display name, when the profile has one. */
52
+ displayName?: string;
53
+ /** Normalized handle — the sanctioned fallback when `displayName` is absent. */
54
+ handle?: string;
55
+ /** Avatar — a URL or bare file id passed straight to `<Avatar source>`. */
56
+ avatarUri?: string;
57
+ }
58
+
59
+ export interface OxyConsentScreenProps {
60
+ /** The resolved requesting application. */
61
+ application: OxyConsentApplication;
62
+ /** OAuth scopes requested by the client (mapped to friendly labels). */
63
+ scopes: string[];
64
+ /** The account that will authorize the request, when known. */
65
+ user?: OxyConsentUser;
66
+ /** Approve handler — the caller mints the code / completes the flow. */
67
+ onAllow: () => void | Promise<void>;
68
+ /** Deny handler — the caller cancels the flow. */
69
+ onDeny: () => void;
70
+ /** True while a decision is in flight; disables both actions and spins Allow. */
71
+ busy?: boolean;
72
+ /** A blocking error message for the request, when present. */
73
+ error?: string | null;
74
+ }
75
+
76
+ /**
77
+ * Friendly-label i18n keys for the scopes the platform issues. Standard OIDC
78
+ * scopes (`openid` / `profile` / `email` / `offline_access`) and the Oxy scope
79
+ * set both map to a curated `consent.scopes.*` sentence. Unknown scopes fall
80
+ * back to the raw scope string so the user always sees something concrete.
81
+ */
82
+ const SCOPE_LABEL_KEYS: Record<string, string> = {
83
+ openid: 'consent.scopes.openid',
84
+ profile: 'consent.scopes.profile',
85
+ email: 'consent.scopes.email',
86
+ offline_access: 'consent.scopes.offlineAccess',
87
+ 'user:read': 'consent.scopes.userRead',
88
+ 'files:read': 'consent.scopes.filesRead',
89
+ 'files:write': 'consent.scopes.filesWrite',
90
+ 'files:delete': 'consent.scopes.filesDelete',
91
+ 'webhooks:receive': 'consent.scopes.webhooksReceive',
92
+ 'chat:completions': 'consent.scopes.chatCompletions',
93
+ 'models:read': 'consent.scopes.modelsRead',
94
+ 'federation:write': 'consent.scopes.federationWrite',
95
+ };
96
+
97
+ type Translate = ReturnType<typeof useI18n>['t'];
98
+
99
+ function scopeLabel(scope: string, t: Translate): string {
100
+ const key = SCOPE_LABEL_KEYS[scope];
101
+ return key ? t(key) : scope;
102
+ }
103
+
104
+ /** A tappable legal/website link that opens the URL in the platform browser. */
105
+ function ConsentLink({
106
+ label,
107
+ url,
108
+ testID,
109
+ color,
110
+ }: {
111
+ label: string;
112
+ url: string;
113
+ testID: string;
114
+ color: string;
115
+ }) {
116
+ const handlePress = useCallback(() => {
117
+ // `websiteUrl`/legal URLs are application-controlled metadata rendered on a
118
+ // high-trust surface: only ever hand web schemes to the OS.
119
+ let protocol: string;
120
+ try {
121
+ protocol = new URL(url).protocol;
122
+ } catch {
123
+ logger.warn('OxyConsentScreen: invalid link URL', { url });
124
+ return;
125
+ }
126
+ if (protocol !== 'https:' && protocol !== 'http:') {
127
+ logger.warn('OxyConsentScreen: blocked non-web link scheme', { url });
128
+ return;
129
+ }
130
+ Linking.openURL(url).catch((error) => {
131
+ logger.warn('OxyConsentScreen: could not open link', { url, error });
132
+ });
133
+ }, [url]);
134
+ return (
135
+ <Pressable testID={testID} onPress={handlePress} accessibilityRole="link" style={styles.link}>
136
+ <Text style={[styles.linkText, { color }]}>{label}</Text>
137
+ </Pressable>
138
+ );
139
+ }
140
+
141
+ export function OxyConsentScreen({
142
+ application,
143
+ scopes,
144
+ user,
145
+ onAllow,
146
+ onDeny,
147
+ busy = false,
148
+ error = null,
149
+ }: OxyConsentScreenProps) {
150
+ const theme = useTheme();
151
+ const { t } = useI18n();
152
+ const appName = application.name;
153
+ // Scopes key the permission rows — a duplicate in the request would mean
154
+ // duplicate React keys and redundant rows.
155
+ const uniqueScopes = [...new Set(scopes)];
156
+
157
+ const provenanceLabel = application.isOfficial
158
+ ? t('consent.provenance.official')
159
+ : application.developerName
160
+ ? t('consent.provenance.developer', { developer: application.developerName })
161
+ : t('consent.provenance.thirdParty');
162
+
163
+ // Display-name rule (D5): a real display name, else the normalized handle.
164
+ const accountName = user ? user.displayName?.trim() || user.handle : undefined;
165
+
166
+ const handleAllow = useCallback(() => {
167
+ void onAllow();
168
+ }, [onAllow]);
169
+
170
+ const showLegalLinks = Boolean(application.privacyPolicyUrl || application.termsUrl);
171
+
172
+ return (
173
+ <ScrollView
174
+ testID="oxy-consent-screen"
175
+ style={styles.root}
176
+ contentContainerStyle={styles.content}
177
+ >
178
+ {/* Header: requesting app ↔ Oxy identity */}
179
+ <View style={styles.header}>
180
+ <View style={styles.connection}>
181
+ <Avatar source={application.iconUrl} name={appName} size={56} />
182
+ <View style={styles.connector}>
183
+ <View style={[styles.dot, { backgroundColor: theme.colors.border }]} />
184
+ <View style={[styles.dot, { backgroundColor: theme.colors.border }]} />
185
+ <View style={[styles.dot, { backgroundColor: theme.colors.border }]} />
186
+ </View>
187
+ <View style={[styles.logoBadge, { backgroundColor: theme.colors.backgroundSecondary ?? theme.colors.card }]}>
188
+ <OxyLogo variant="icon" size={30} fillColor={theme.colors.primary} />
189
+ </View>
190
+ </View>
191
+ <Text style={[styles.title, { color: theme.colors.text }]}>
192
+ {t('consent.title', { app: appName })}
193
+ </Text>
194
+ <Text style={[styles.subtitle, { color: theme.colors.textSecondary }]}>
195
+ {t('consent.subtitle', { app: appName })}
196
+ </Text>
197
+ </View>
198
+
199
+ {/* Provenance */}
200
+ <View style={[styles.card, { borderColor: theme.colors.border, backgroundColor: theme.colors.card }]}>
201
+ <Text testID="consent-provenance" style={[styles.provenance, { color: theme.colors.text }]}>
202
+ {provenanceLabel}
203
+ </Text>
204
+ {application.websiteUrl ? (
205
+ <ConsentLink
206
+ testID="consent-link-website"
207
+ label={application.websiteUrl}
208
+ url={application.websiteUrl}
209
+ color={theme.colors.primary}
210
+ />
211
+ ) : null}
212
+ </View>
213
+
214
+ {/* Requested permissions */}
215
+ <View style={styles.section}>
216
+ <Text style={[styles.sectionLabel, { color: theme.colors.textSecondary }]}>
217
+ {t('consent.permissions.title')}
218
+ </Text>
219
+ <View style={[styles.card, { borderColor: theme.colors.border, backgroundColor: theme.colors.card }]}>
220
+ {uniqueScopes.length > 0 ? (
221
+ uniqueScopes.map((scope) => (
222
+ <View key={scope} testID={`consent-scope-${scope}`} style={styles.row}>
223
+ <View style={[styles.bullet, { backgroundColor: theme.colors.primary }]} />
224
+ <Text style={[styles.rowText, { color: theme.colors.text }]}>
225
+ {scopeLabel(scope, t)}
226
+ </Text>
227
+ </View>
228
+ ))
229
+ ) : (
230
+ <View testID="consent-scope-basic" style={styles.row}>
231
+ <View style={[styles.bullet, { backgroundColor: theme.colors.primary }]} />
232
+ <Text style={[styles.rowText, { color: theme.colors.text }]}>
233
+ {t('consent.permissions.basic')}
234
+ </Text>
235
+ </View>
236
+ )}
237
+ </View>
238
+ </View>
239
+
240
+ {/* Authorizing account */}
241
+ {user ? (
242
+ <View
243
+ testID="consent-account"
244
+ style={[styles.accountRow, { borderColor: theme.colors.border, backgroundColor: theme.colors.card }]}
245
+ >
246
+ <Avatar source={user.avatarUri} name={accountName} size={40} />
247
+ <View style={styles.accountText}>
248
+ <Text
249
+ testID="consent-account-name"
250
+ numberOfLines={1}
251
+ style={[styles.accountName, { color: theme.colors.text }]}
252
+ >
253
+ {accountName}
254
+ </Text>
255
+ {user.handle && user.handle !== accountName ? (
256
+ <Text numberOfLines={1} style={[styles.accountHandle, { color: theme.colors.textSecondary }]}>
257
+ {user.handle}
258
+ </Text>
259
+ ) : null}
260
+ </View>
261
+ </View>
262
+ ) : null}
263
+
264
+ {/* Legal links */}
265
+ {showLegalLinks ? (
266
+ <View style={styles.linksRow}>
267
+ {application.privacyPolicyUrl ? (
268
+ <ConsentLink
269
+ testID="consent-link-privacy"
270
+ label={t('consent.links.privacy')}
271
+ url={application.privacyPolicyUrl}
272
+ color={theme.colors.textSecondary}
273
+ />
274
+ ) : null}
275
+ {application.termsUrl ? (
276
+ <ConsentLink
277
+ testID="consent-link-terms"
278
+ label={t('consent.links.terms')}
279
+ url={application.termsUrl}
280
+ color={theme.colors.textSecondary}
281
+ />
282
+ ) : null}
283
+ </View>
284
+ ) : null}
285
+
286
+ {/* Blocking error */}
287
+ {error ? (
288
+ <View
289
+ testID="consent-error"
290
+ style={[styles.errorCard, { borderColor: theme.colors.error }]}
291
+ >
292
+ <Text style={[styles.errorText, { color: theme.colors.error }]}>{error}</Text>
293
+ </View>
294
+ ) : null}
295
+
296
+ {/* Decision actions */}
297
+ <View style={styles.actions}>
298
+ <Button
299
+ testID="consent-allow"
300
+ variant="primary"
301
+ onPress={handleAllow}
302
+ disabled={busy}
303
+ loading={busy}
304
+ style={styles.actionButton}
305
+ >
306
+ {t('consent.allow', { app: appName })}
307
+ </Button>
308
+ <Button
309
+ testID="consent-deny"
310
+ variant="ghost"
311
+ onPress={onDeny}
312
+ disabled={busy}
313
+ style={styles.actionButton}
314
+ >
315
+ {t('consent.deny')}
316
+ </Button>
317
+ </View>
318
+
319
+ <Text style={[styles.disclaimer, { color: theme.colors.textSecondary }]}>
320
+ {t('consent.disclaimer', { app: appName })}
321
+ </Text>
322
+ </ScrollView>
323
+ );
324
+ }
325
+
326
+ const styles = StyleSheet.create({
327
+ root: {
328
+ flex: 1,
329
+ },
330
+ content: {
331
+ padding: 20,
332
+ gap: 20,
333
+ },
334
+ header: {
335
+ alignItems: 'center',
336
+ gap: 12,
337
+ },
338
+ connection: {
339
+ flexDirection: 'row',
340
+ alignItems: 'center',
341
+ gap: 10,
342
+ },
343
+ connector: {
344
+ flexDirection: 'row',
345
+ alignItems: 'center',
346
+ gap: 4,
347
+ },
348
+ dot: {
349
+ width: 4,
350
+ height: 4,
351
+ borderRadius: 2,
352
+ },
353
+ logoBadge: {
354
+ width: 56,
355
+ height: 56,
356
+ borderRadius: 28,
357
+ alignItems: 'center',
358
+ justifyContent: 'center',
359
+ },
360
+ title: {
361
+ fontSize: 20,
362
+ fontWeight: '700',
363
+ textAlign: 'center',
364
+ },
365
+ subtitle: {
366
+ fontSize: 14,
367
+ lineHeight: 20,
368
+ textAlign: 'center',
369
+ },
370
+ section: {
371
+ gap: 8,
372
+ },
373
+ sectionLabel: {
374
+ fontSize: 12,
375
+ fontWeight: '600',
376
+ paddingHorizontal: 4,
377
+ },
378
+ card: {
379
+ borderWidth: StyleSheet.hairlineWidth,
380
+ borderRadius: 16,
381
+ padding: 12,
382
+ gap: 10,
383
+ },
384
+ provenance: {
385
+ fontSize: 14,
386
+ fontWeight: '600',
387
+ },
388
+ row: {
389
+ flexDirection: 'row',
390
+ alignItems: 'center',
391
+ gap: 10,
392
+ },
393
+ bullet: {
394
+ width: 6,
395
+ height: 6,
396
+ borderRadius: 3,
397
+ },
398
+ rowText: {
399
+ flex: 1,
400
+ fontSize: 14,
401
+ },
402
+ accountRow: {
403
+ flexDirection: 'row',
404
+ alignItems: 'center',
405
+ gap: 12,
406
+ borderWidth: StyleSheet.hairlineWidth,
407
+ borderRadius: 16,
408
+ padding: 12,
409
+ },
410
+ accountText: {
411
+ flex: 1,
412
+ minWidth: 0,
413
+ },
414
+ accountName: {
415
+ fontSize: 15,
416
+ fontWeight: '600',
417
+ },
418
+ accountHandle: {
419
+ fontSize: 13,
420
+ },
421
+ linksRow: {
422
+ flexDirection: 'row',
423
+ flexWrap: 'wrap',
424
+ gap: 16,
425
+ paddingHorizontal: 4,
426
+ },
427
+ link: {
428
+ alignSelf: 'flex-start',
429
+ },
430
+ linkText: {
431
+ fontSize: 13,
432
+ textDecorationLine: 'underline',
433
+ },
434
+ errorCard: {
435
+ borderWidth: StyleSheet.hairlineWidth,
436
+ borderRadius: 12,
437
+ padding: 12,
438
+ },
439
+ errorText: {
440
+ fontSize: 14,
441
+ },
442
+ actions: {
443
+ gap: 12,
444
+ },
445
+ actionButton: {
446
+ width: '100%',
447
+ },
448
+ disclaimer: {
449
+ fontSize: 12,
450
+ lineHeight: 18,
451
+ textAlign: 'center',
452
+ paddingHorizontal: 4,
453
+ },
454
+ });
455
+
456
+ export default OxyConsentScreen;
@@ -9,6 +9,7 @@ import { BloomDialogProvider } from '@oxyhq/bloom';
9
9
  import { ToastOutlet } from '@oxyhq/bloom/toast';
10
10
  import { logger as loggerUtil } from '@oxyhq/core';
11
11
  import { setupFonts } from './FontLoader';
12
+ import { RequireOxyAuth } from './RequireOxyAuth';
12
13
  import { attachQueryPersistence, createQueryClient } from '../hooks/queryClient';
13
14
  import { createPlatformStorage, type StorageInterface } from '../utils/storageHelpers';
14
15
 
@@ -63,8 +64,8 @@ const LazyBottomSheetRouter = lazy((): Promise<{ default: ComponentType }> =>
63
64
  ),
64
65
  );
65
66
 
66
- const LazySignInModal = lazy((): Promise<{ default: ComponentType }> =>
67
- import('./SignInModal').then(
67
+ const LazyOxyAccountDialog = lazy((): Promise<{ default: ComponentType }> =>
68
+ import('./OxyAccountDialog').then(
68
69
  (mod) => ({ default: mod.default as unknown as ComponentType }),
69
70
  () => ({ default: (() => null) as FC }),
70
71
  ),
@@ -75,8 +76,8 @@ const LazySignInModal = lazy((): Promise<{ default: ComponentType }> =>
75
76
  *
76
77
  * Provides authentication, session management, query client, and UI overlays.
77
78
  * Wraps its own overlay stack in SafeAreaProvider and GestureHandlerRootView so
78
- * BottomSheetRouter and SignInModal can safely render even when a consuming app
79
- * has not mounted those providers yet.
79
+ * BottomSheetRouter and OxyAccountDialog can safely render even when a consuming
80
+ * app has not mounted those providers yet.
80
81
  *
81
82
  * Usage:
82
83
  * ```tsx
@@ -114,6 +115,8 @@ const OxyProvider: FC<OxyProviderProps> = ({
114
115
  authWebUrl,
115
116
  authRedirectUri,
116
117
  queryClient: providedQueryClient,
118
+ requireAuth = 'off',
119
+ coldBoot = true,
117
120
  }) => {
118
121
 
119
122
  // Dynamic KeyboardProvider for native. Uses variable indirection
@@ -308,12 +311,17 @@ const OxyProvider: FC<OxyProviderProps> = ({
308
311
  authRedirectUri={authRedirectUri}
309
312
  storageKeyPrefix={storageKeyPrefix}
310
313
  clientId={clientId}
314
+ coldBoot={coldBoot}
311
315
  onAuthStateChange={onAuthStateChange as OxyContextProviderProps['onAuthStateChange']}
312
316
  >
313
- {children}
317
+ {requireAuth === 'off' ? (
318
+ children
319
+ ) : (
320
+ <RequireOxyAuth prompt={requireAuth}>{children}</RequireOxyAuth>
321
+ )}
314
322
  <Suspense fallback={null}>
315
323
  <LazyBottomSheetRouter />
316
- <LazySignInModal />
324
+ <LazyOxyAccountDialog />
317
325
  </Suspense>
318
326
  <ToastOutlet />
319
327
  </OxyContextProvider>