@oxyhq/services 27.1.3 → 29.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 (387) hide show
  1. package/LICENSE +202 -661
  2. package/NOTICE +16 -0
  3. package/README.md +67 -2
  4. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionModule.kt +178 -0
  5. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionProvider.kt +99 -0
  6. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionStore.kt +115 -0
  7. package/expo-module.config.json +1 -0
  8. package/lib/commonjs/index.js +78 -16
  9. package/lib/commonjs/index.js.map +1 -1
  10. package/lib/commonjs/ui/boot/runProviderColdBoot.js +7 -0
  11. package/lib/commonjs/ui/boot/runProviderColdBoot.js.map +1 -1
  12. package/lib/commonjs/ui/client.js +12 -7
  13. package/lib/commonjs/ui/client.js.map +1 -1
  14. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +10 -27
  15. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
  16. package/lib/commonjs/ui/components/OxyAuthChooser.js +132 -44
  17. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  18. package/lib/commonjs/ui/components/OxyProvider.js +4 -2
  19. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  20. package/lib/commonjs/ui/components/SurfaceScreen.js +31 -3
  21. package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
  22. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +209 -84
  23. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  24. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js +25 -7
  25. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js.map +1 -1
  26. package/lib/commonjs/ui/components/authChooser/primitives.js +35 -22
  27. package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
  28. package/lib/commonjs/ui/components/authChooser/signInProgress.js +5 -0
  29. package/lib/commonjs/ui/components/authChooser/signInProgress.js.map +1 -1
  30. package/lib/commonjs/ui/components/authChooser/types.js +11 -0
  31. package/lib/commonjs/ui/components/authChooser/types.js.map +1 -1
  32. package/lib/commonjs/ui/context/OxyContext.js +257 -306
  33. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  34. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +27 -37
  35. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  36. package/lib/commonjs/ui/context/oxyContextHelpers.js +0 -29
  37. package/lib/commonjs/ui/context/oxyContextHelpers.js.map +1 -1
  38. package/lib/commonjs/ui/context/useOxyAccountGraph.js +6 -17
  39. package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
  40. package/lib/commonjs/ui/hooks/accountDialogSnapshot.js +42 -0
  41. package/lib/commonjs/ui/hooks/accountDialogSnapshot.js.map +1 -0
  42. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +0 -19
  43. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  44. package/lib/commonjs/ui/hooks/useDeviceSwitcher.js +57 -0
  45. package/lib/commonjs/ui/hooks/useDeviceSwitcher.js.map +1 -0
  46. package/lib/commonjs/ui/hooks/useI18n.js +22 -3
  47. package/lib/commonjs/ui/hooks/useI18n.js.map +1 -1
  48. package/lib/commonjs/ui/hooks/useSessionManagement.js +46 -153
  49. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  50. package/lib/commonjs/ui/index.js +12 -7
  51. package/lib/commonjs/ui/index.js.map +1 -1
  52. package/lib/commonjs/ui/navigation/routes.js +85 -73
  53. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  54. package/lib/commonjs/ui/navigation/surfaces.js +8 -7
  55. package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
  56. package/lib/commonjs/ui/runtime/createOxyRuntime.js +433 -0
  57. package/lib/commonjs/ui/runtime/createOxyRuntime.js.map +1 -0
  58. package/lib/commonjs/ui/runtime/index.js +63 -0
  59. package/lib/commonjs/ui/runtime/index.js.map +1 -0
  60. package/lib/commonjs/ui/runtime/runtimeContext.js +83 -0
  61. package/lib/commonjs/ui/runtime/runtimeContext.js.map +1 -0
  62. package/lib/commonjs/ui/runtime/types.js +6 -0
  63. package/lib/commonjs/ui/runtime/types.js.map +1 -0
  64. package/lib/commonjs/ui/runtime/useRuntimeSnapshot.js +57 -0
  65. package/lib/commonjs/ui/runtime/useRuntimeSnapshot.js.map +1 -0
  66. package/lib/commonjs/ui/screens/AccountMembersScreen.js +3 -4
  67. package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
  68. package/lib/commonjs/ui/screens/CreateAccountScreen.js +3 -12
  69. package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
  70. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +6 -5
  71. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  72. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +4 -4
  73. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  74. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +1 -1
  75. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +4 -2
  76. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  77. package/lib/commonjs/ui/server.js +1 -2
  78. package/lib/commonjs/ui/server.js.map +1 -1
  79. package/lib/commonjs/ui/session/authStore.js +45 -9
  80. package/lib/commonjs/ui/session/authStore.js.map +1 -1
  81. package/lib/commonjs/ui/session/sharedDeviceCredentialStore.js +306 -0
  82. package/lib/commonjs/ui/session/sharedDeviceCredentialStore.js.map +1 -0
  83. package/lib/commonjs/ui/stores/authStore.js +154 -55
  84. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  85. package/lib/commonjs/ui/stores/followTargetStore.js +27 -0
  86. package/lib/commonjs/ui/stores/followTargetStore.js.map +1 -1
  87. package/lib/commonjs/ui/utils/avatarUtils.js +2 -36
  88. package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
  89. package/lib/module/index.js +20 -9
  90. package/lib/module/index.js.map +1 -1
  91. package/lib/module/ui/boot/runProviderColdBoot.js +7 -0
  92. package/lib/module/ui/boot/runProviderColdBoot.js.map +1 -1
  93. package/lib/module/ui/client.js +1 -2
  94. package/lib/module/ui/client.js.map +1 -1
  95. package/lib/module/ui/components/OxyAccountDialogScreen.js +10 -27
  96. package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
  97. package/lib/module/ui/components/OxyAuthChooser.js +134 -44
  98. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  99. package/lib/module/ui/components/OxyProvider.js +5 -3
  100. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  101. package/lib/module/ui/components/SurfaceScreen.js +33 -5
  102. package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
  103. package/lib/module/ui/components/authChooser/AccountsMenuView.js +210 -85
  104. package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  105. package/lib/module/ui/components/authChooser/SignInEntryView.js +25 -7
  106. package/lib/module/ui/components/authChooser/SignInEntryView.js.map +1 -1
  107. package/lib/module/ui/components/authChooser/primitives.js +35 -22
  108. package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
  109. package/lib/module/ui/components/authChooser/signInProgress.js +5 -0
  110. package/lib/module/ui/components/authChooser/signInProgress.js.map +1 -1
  111. package/lib/module/ui/components/authChooser/types.js +11 -0
  112. package/lib/module/ui/components/authChooser/types.js.map +1 -1
  113. package/lib/module/ui/context/OxyContext.js +251 -303
  114. package/lib/module/ui/context/OxyContext.js.map +1 -1
  115. package/lib/module/ui/context/hooks/useAuthOperations.js +27 -37
  116. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  117. package/lib/module/ui/context/oxyContextHelpers.js +0 -28
  118. package/lib/module/ui/context/oxyContextHelpers.js.map +1 -1
  119. package/lib/module/ui/context/useOxyAccountGraph.js +6 -17
  120. package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
  121. package/lib/module/ui/hooks/accountDialogSnapshot.js +38 -0
  122. package/lib/module/ui/hooks/accountDialogSnapshot.js.map +1 -0
  123. package/lib/module/ui/hooks/mutations/useAccountMutations.js +0 -19
  124. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  125. package/lib/module/ui/hooks/useDeviceSwitcher.js +53 -0
  126. package/lib/module/ui/hooks/useDeviceSwitcher.js.map +1 -0
  127. package/lib/module/ui/hooks/useI18n.js +24 -4
  128. package/lib/module/ui/hooks/useI18n.js.map +1 -1
  129. package/lib/module/ui/hooks/useSessionManagement.js +47 -155
  130. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  131. package/lib/module/ui/index.js +1 -2
  132. package/lib/module/ui/index.js.map +1 -1
  133. package/lib/module/ui/navigation/routes.js +84 -72
  134. package/lib/module/ui/navigation/routes.js.map +1 -1
  135. package/lib/module/ui/navigation/surfaces.js +6 -6
  136. package/lib/module/ui/navigation/surfaces.js.map +1 -1
  137. package/lib/module/ui/runtime/createOxyRuntime.js +430 -0
  138. package/lib/module/ui/runtime/createOxyRuntime.js.map +1 -0
  139. package/lib/module/ui/runtime/index.js +15 -0
  140. package/lib/module/ui/runtime/index.js.map +1 -0
  141. package/lib/module/ui/runtime/runtimeContext.js +75 -0
  142. package/lib/module/ui/runtime/runtimeContext.js.map +1 -0
  143. package/lib/module/ui/runtime/types.js +4 -0
  144. package/lib/module/ui/runtime/types.js.map +1 -0
  145. package/lib/module/ui/runtime/useRuntimeSnapshot.js +52 -0
  146. package/lib/module/ui/runtime/useRuntimeSnapshot.js.map +1 -0
  147. package/lib/module/ui/screens/AccountMembersScreen.js +4 -5
  148. package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
  149. package/lib/module/ui/screens/CreateAccountScreen.js +4 -13
  150. package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
  151. package/lib/module/ui/screens/trust/TrustCenterScreen.js +6 -5
  152. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  153. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +5 -5
  154. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  155. package/lib/module/ui/screens/trust/TrustRewardsScreen.js +1 -1
  156. package/lib/module/ui/screens/trust/TrustRulesScreen.js +4 -2
  157. package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  158. package/lib/module/ui/server.js +0 -1
  159. package/lib/module/ui/server.js.map +1 -1
  160. package/lib/module/ui/session/authStore.js +46 -11
  161. package/lib/module/ui/session/authStore.js.map +1 -1
  162. package/lib/module/ui/session/sharedDeviceCredentialStore.js +302 -0
  163. package/lib/module/ui/session/sharedDeviceCredentialStore.js.map +1 -0
  164. package/lib/module/ui/stores/authStore.js +154 -55
  165. package/lib/module/ui/stores/authStore.js.map +1 -1
  166. package/lib/module/ui/stores/followTargetStore.js +25 -0
  167. package/lib/module/ui/stores/followTargetStore.js.map +1 -1
  168. package/lib/module/ui/utils/avatarUtils.js +2 -35
  169. package/lib/module/ui/utils/avatarUtils.js.map +1 -1
  170. package/lib/typescript/commonjs/index.d.ts +6 -4
  171. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  172. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/ui/client.d.ts +1 -2
  174. package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  176. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  177. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  178. package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
  179. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts +11 -4
  180. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  181. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts +3 -1
  182. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts.map +1 -1
  183. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +18 -6
  184. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -1
  185. package/lib/typescript/commonjs/ui/components/authChooser/signInProgress.d.ts.map +1 -1
  186. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +33 -1
  187. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts.map +1 -1
  188. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +35 -4
  189. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  190. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +8 -12
  191. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  192. package/lib/typescript/commonjs/ui/context/oxyContextHelpers.d.ts +0 -2
  193. package/lib/typescript/commonjs/ui/context/oxyContextHelpers.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +9 -1
  195. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
  196. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts +1 -3
  197. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  198. package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts +15 -0
  199. package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts.map +1 -0
  200. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  201. package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts +49 -0
  202. package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts.map +1 -0
  203. package/lib/typescript/commonjs/ui/hooks/useI18n.d.ts +13 -0
  204. package/lib/typescript/commonjs/ui/hooks/useI18n.d.ts.map +1 -1
  205. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts +23 -18
  206. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
  207. package/lib/typescript/commonjs/ui/index.d.ts +1 -2
  208. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  209. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +15 -1
  210. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  211. package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
  212. package/lib/typescript/commonjs/ui/runtime/createOxyRuntime.d.ts +144 -0
  213. package/lib/typescript/commonjs/ui/runtime/createOxyRuntime.d.ts.map +1 -0
  214. package/lib/typescript/commonjs/ui/runtime/index.d.ts +16 -0
  215. package/lib/typescript/commonjs/ui/runtime/index.d.ts.map +1 -0
  216. package/lib/typescript/commonjs/ui/runtime/runtimeContext.d.ts +43 -0
  217. package/lib/typescript/commonjs/ui/runtime/runtimeContext.d.ts.map +1 -0
  218. package/lib/typescript/commonjs/ui/runtime/types.d.ts +89 -0
  219. package/lib/typescript/commonjs/ui/runtime/types.d.ts.map +1 -0
  220. package/lib/typescript/commonjs/ui/runtime/useRuntimeSnapshot.d.ts +23 -0
  221. package/lib/typescript/commonjs/ui/runtime/useRuntimeSnapshot.d.ts.map +1 -0
  222. package/lib/typescript/commonjs/ui/screens/AccountMembersScreen.d.ts.map +1 -1
  223. package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  224. package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  225. package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
  226. package/lib/typescript/commonjs/ui/server.d.ts +0 -1
  227. package/lib/typescript/commonjs/ui/server.d.ts.map +1 -1
  228. package/lib/typescript/commonjs/ui/session/authStore.d.ts +60 -9
  229. package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
  230. package/lib/typescript/commonjs/ui/session/sharedDeviceCredentialStore.d.ts +32 -0
  231. package/lib/typescript/commonjs/ui/session/sharedDeviceCredentialStore.d.ts.map +1 -0
  232. package/lib/typescript/commonjs/ui/stores/authStore.d.ts +49 -5
  233. package/lib/typescript/commonjs/ui/stores/authStore.d.ts.map +1 -1
  234. package/lib/typescript/commonjs/ui/stores/followTargetStore.d.ts +8 -1
  235. package/lib/typescript/commonjs/ui/stores/followTargetStore.d.ts.map +1 -1
  236. package/lib/typescript/commonjs/ui/types/navigation.d.ts +26 -0
  237. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  238. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts +2 -10
  239. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
  240. package/lib/typescript/module/index.d.ts +6 -4
  241. package/lib/typescript/module/index.d.ts.map +1 -1
  242. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  243. package/lib/typescript/module/ui/client.d.ts +1 -2
  244. package/lib/typescript/module/ui/client.d.ts.map +1 -1
  245. package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  246. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  247. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  248. package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
  249. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts +11 -4
  250. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  251. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts +3 -1
  252. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts.map +1 -1
  253. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +18 -6
  254. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -1
  255. package/lib/typescript/module/ui/components/authChooser/signInProgress.d.ts.map +1 -1
  256. package/lib/typescript/module/ui/components/authChooser/types.d.ts +33 -1
  257. package/lib/typescript/module/ui/components/authChooser/types.d.ts.map +1 -1
  258. package/lib/typescript/module/ui/context/OxyContext.d.ts +35 -4
  259. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  260. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +8 -12
  261. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  262. package/lib/typescript/module/ui/context/oxyContextHelpers.d.ts +0 -2
  263. package/lib/typescript/module/ui/context/oxyContextHelpers.d.ts.map +1 -1
  264. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +9 -1
  265. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
  266. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts +1 -3
  267. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  268. package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts +15 -0
  269. package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts.map +1 -0
  270. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  271. package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts +49 -0
  272. package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts.map +1 -0
  273. package/lib/typescript/module/ui/hooks/useI18n.d.ts +13 -0
  274. package/lib/typescript/module/ui/hooks/useI18n.d.ts.map +1 -1
  275. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts +23 -18
  276. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
  277. package/lib/typescript/module/ui/index.d.ts +1 -2
  278. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  279. package/lib/typescript/module/ui/navigation/routes.d.ts +15 -1
  280. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  281. package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
  282. package/lib/typescript/module/ui/runtime/createOxyRuntime.d.ts +144 -0
  283. package/lib/typescript/module/ui/runtime/createOxyRuntime.d.ts.map +1 -0
  284. package/lib/typescript/module/ui/runtime/index.d.ts +16 -0
  285. package/lib/typescript/module/ui/runtime/index.d.ts.map +1 -0
  286. package/lib/typescript/module/ui/runtime/runtimeContext.d.ts +43 -0
  287. package/lib/typescript/module/ui/runtime/runtimeContext.d.ts.map +1 -0
  288. package/lib/typescript/module/ui/runtime/types.d.ts +89 -0
  289. package/lib/typescript/module/ui/runtime/types.d.ts.map +1 -0
  290. package/lib/typescript/module/ui/runtime/useRuntimeSnapshot.d.ts +23 -0
  291. package/lib/typescript/module/ui/runtime/useRuntimeSnapshot.d.ts.map +1 -0
  292. package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts.map +1 -1
  293. package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  294. package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  295. package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
  296. package/lib/typescript/module/ui/server.d.ts +0 -1
  297. package/lib/typescript/module/ui/server.d.ts.map +1 -1
  298. package/lib/typescript/module/ui/session/authStore.d.ts +60 -9
  299. package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
  300. package/lib/typescript/module/ui/session/sharedDeviceCredentialStore.d.ts +32 -0
  301. package/lib/typescript/module/ui/session/sharedDeviceCredentialStore.d.ts.map +1 -0
  302. package/lib/typescript/module/ui/stores/authStore.d.ts +49 -5
  303. package/lib/typescript/module/ui/stores/authStore.d.ts.map +1 -1
  304. package/lib/typescript/module/ui/stores/followTargetStore.d.ts +8 -1
  305. package/lib/typescript/module/ui/stores/followTargetStore.d.ts.map +1 -1
  306. package/lib/typescript/module/ui/types/navigation.d.ts +26 -0
  307. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  308. package/lib/typescript/module/ui/utils/avatarUtils.d.ts +2 -10
  309. package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
  310. package/package.json +8 -8
  311. package/plugins/withSharedDeviceSessionProvider.js +102 -0
  312. package/plugins/withSharedDeviceSessionReader.js +57 -0
  313. package/src/__tests__/esmSourcePurity.test.ts +61 -0
  314. package/src/index.ts +36 -9
  315. package/src/ui/boot/runProviderColdBoot.ts +7 -0
  316. package/src/ui/client.ts +1 -2
  317. package/src/ui/components/OxyAccountDialogScreen.tsx +10 -29
  318. package/src/ui/components/OxyAuthChooser.tsx +149 -50
  319. package/src/ui/components/OxyProvider.tsx +7 -5
  320. package/src/ui/components/SurfaceScreen.tsx +28 -4
  321. package/src/ui/components/__tests__/followTargetButton.test.ts +39 -0
  322. package/src/ui/components/authChooser/AccountsMenuView.tsx +246 -96
  323. package/src/ui/components/authChooser/SignInEntryView.tsx +31 -8
  324. package/src/ui/components/authChooser/primitives.tsx +37 -23
  325. package/src/ui/components/authChooser/signInProgress.ts +4 -0
  326. package/src/ui/components/authChooser/types.ts +34 -1
  327. package/src/ui/context/OxyContext.tsx +269 -324
  328. package/src/ui/context/hooks/useAuthOperations.ts +32 -35
  329. package/src/ui/context/oxyContextHelpers.ts +0 -30
  330. package/src/ui/context/oxyContextTypes.ts +9 -1
  331. package/src/ui/context/useOxyAccountGraph.ts +5 -19
  332. package/src/ui/hooks/accountDialogSnapshot.ts +37 -0
  333. package/src/ui/hooks/mutations/useAccountMutations.ts +0 -19
  334. package/src/ui/hooks/queries/__tests__/userCache.test.ts +12 -1
  335. package/src/ui/hooks/useDeviceSwitcher.ts +110 -0
  336. package/src/ui/hooks/useI18n.ts +23 -3
  337. package/src/ui/hooks/useSessionManagement.ts +62 -211
  338. package/src/ui/index.ts +1 -2
  339. package/src/ui/navigation/routes.ts +85 -75
  340. package/src/ui/navigation/surfaces.ts +6 -9
  341. package/src/ui/runtime/createOxyRuntime.ts +623 -0
  342. package/src/ui/runtime/index.ts +34 -0
  343. package/src/ui/runtime/runtimeContext.tsx +111 -0
  344. package/src/ui/runtime/types.ts +110 -0
  345. package/src/ui/runtime/useRuntimeSnapshot.ts +52 -0
  346. package/src/ui/screens/AccountMembersScreen.tsx +6 -5
  347. package/src/ui/screens/CreateAccountScreen.tsx +3 -16
  348. package/src/ui/screens/trust/TrustCenterScreen.tsx +7 -7
  349. package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +4 -5
  350. package/src/ui/screens/trust/TrustRewardsScreen.tsx +1 -1
  351. package/src/ui/screens/trust/TrustRulesScreen.tsx +3 -2
  352. package/src/ui/server.ts +0 -1
  353. package/src/ui/session/__tests__/authStore.test.ts +90 -0
  354. package/src/ui/session/__tests__/sharedDeviceCredentialStore.test.ts +289 -0
  355. package/src/ui/session/authStore.ts +78 -9
  356. package/src/ui/session/sharedDeviceCredentialStore.ts +318 -0
  357. package/src/ui/stores/authStore.ts +171 -43
  358. package/src/ui/stores/followTargetStore.ts +24 -1
  359. package/src/ui/types/navigation.ts +26 -0
  360. package/src/ui/utils/avatarUtils.ts +2 -37
  361. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +0 -64
  362. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +0 -1
  363. package/lib/commonjs/ui/screens/trust/trustTier.js +0 -23
  364. package/lib/commonjs/ui/screens/trust/trustTier.js.map +0 -1
  365. package/lib/commonjs/ui/stores/accountStore.js +0 -221
  366. package/lib/commonjs/ui/stores/accountStore.js.map +0 -1
  367. package/lib/module/ui/hooks/useSwitchableAccounts.js +0 -60
  368. package/lib/module/ui/hooks/useSwitchableAccounts.js.map +0 -1
  369. package/lib/module/ui/screens/trust/trustTier.js +0 -19
  370. package/lib/module/ui/screens/trust/trustTier.js.map +0 -1
  371. package/lib/module/ui/stores/accountStore.js +0 -213
  372. package/lib/module/ui/stores/accountStore.js.map +0 -1
  373. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +0 -23
  374. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +0 -1
  375. package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts +0 -9
  376. package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts.map +0 -1
  377. package/lib/typescript/commonjs/ui/stores/accountStore.d.ts +0 -27
  378. package/lib/typescript/commonjs/ui/stores/accountStore.d.ts.map +0 -1
  379. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +0 -23
  380. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +0 -1
  381. package/lib/typescript/module/ui/screens/trust/trustTier.d.ts +0 -9
  382. package/lib/typescript/module/ui/screens/trust/trustTier.d.ts.map +0 -1
  383. package/lib/typescript/module/ui/stores/accountStore.d.ts +0 -27
  384. package/lib/typescript/module/ui/stores/accountStore.d.ts.map +0 -1
  385. package/src/ui/hooks/useSwitchableAccounts.ts +0 -75
  386. package/src/ui/screens/trust/trustTier.ts +0 -20
  387. package/src/ui/stores/accountStore.ts +0 -264
@@ -13,8 +13,7 @@ import { isWebBrowser } from "../utils/isWebBrowser.js";
13
13
  import { resolveDeliveryPlatform } from "../utils/deliveryPlatform.js";
14
14
  import { runProviderColdBoot } from "../boot/runProviderColdBoot.js";
15
15
  import { loadPersistedDeviceCredential } from "../utils/deviceCredential.js";
16
- import { useAuthStore } from "../stores/authStore.js";
17
- import { useShallow } from 'zustand/react/shallow';
16
+ import { bindAuthStoreToRuntime } from "../stores/authStore.js";
18
17
  import { useLanguageManagement } from "../hooks/useLanguageManagement.js";
19
18
  import { useSessionManagement } from "../hooks/useSessionManagement.js";
20
19
  import { useAuthOperations, clearPersistedAuthSafe } from "./hooks/useAuthOperations.js";
@@ -25,17 +24,35 @@ import { presentDetached, topRouteSurface } from "../navigation/surfaces.js";
25
24
  import { useQueryClient, onlineManager } from '@tanstack/react-query';
26
25
  import { clearQueryCache } from "../hooks/queryClient.js";
27
26
  import { useAvatarPicker } from "../hooks/useAvatarPicker.js";
28
- import { useAccountStore } from "../stores/accountStore.js";
29
- import { createSessionClient, createIdentitySessionBinding, createPlatformAuthStateStore, deviceStateToClientSessions, activeSessionIdOf, activeUserOf, accountIdsOf, IdentityBoundSessionError, useBackgroundSessionSync } from "../session/index.js";
30
- import { DEFAULT_SESSION_VALIDITY_MS, loadUseFollowHook } from "./oxyContextHelpers.js";
27
+ import { resetSessionScopedStores } from "../stores/resetSessionScopedStores.js";
28
+ import { ASSET_DOWNLOAD_URLS_QUERY_KEY } from "../hooks/useResolvedFileUrls.js";
29
+ import { createOxyRuntime, OxyRuntimeHandleProvider, useRuntimeSnapshot } from "../runtime/index.js";
30
+ import { createSessionClient, createIdentitySessionBinding, createPlatformAuthStateStore, IdentityBoundSessionError, useBackgroundSessionSync } from "../session/index.js";
31
+ import { DEFAULT_SESSION_VALIDITY_MS } from "./oxyContextHelpers.js";
32
+ // `useFollow` imports this module back, so the binding must only be READ inside
33
+ // the provider body — at render time, once every module has evaluated. It is
34
+ // never dereferenced at module scope here.
35
+ import { useFollow } from "../hooks/useFollow.js";
31
36
  import { commitDeviceSetAndResolve } from "./commitSessionFlow.js";
32
37
  import { runPasskeyLogin, runPasskeyRegister, runPasskeyAdd } from "./passkeyFlow.js";
33
38
  import { isPasskeySupported, runRegistrationCeremony, runAuthenticationCeremony } from '../../webauthn/passkeyClient';
34
39
  import { queryKeys } from "../hooks/queries/queryKeys.js";
35
40
  import { useOxyAccountGraph } from "./useOxyAccountGraph.js";
36
41
  import { jsx as _jsx } from "react/jsx-runtime";
37
- const OxyContext = /*#__PURE__*/createContext(null);
38
- export const OxyProvider = ({
42
+ const OxyRuntimeContext = /*#__PURE__*/createContext(null);
43
+
44
+ /**
45
+ * The SDK's internal runtime provider — the session/account state machine that
46
+ * backs `useOxy()`.
47
+ *
48
+ * This is NOT the component consumers mount. The one public composition root is
49
+ * `OxyProvider` (`../components/OxyProvider`), which mounts this alongside the
50
+ * QueryClient, Bloom's dialog/surface/toast hosts, safe areas, the gesture root
51
+ * and the keyboard provider. Naming both of them `OxyProvider` (as this file
52
+ * used to) made every error message, stack frame and doc reference ambiguous —
53
+ * see ADR 0004.
54
+ */
55
+ export const OxyRuntimeProvider = ({
39
56
  children,
40
57
  oxyServices: providedOxyServices,
41
58
  baseURL,
@@ -47,6 +64,7 @@ export const OxyProvider = ({
47
64
  sessionMode = 'account',
48
65
  webAuthMode = 'popup',
49
66
  backgroundSession = false,
67
+ deviceCredentialStorage = 'persistent',
50
68
  onAuthStateChange,
51
69
  onError
52
70
  }) => {
@@ -63,17 +81,24 @@ export const OxyProvider = ({
63
81
  authRedirectUri
64
82
  });
65
83
  } else {
66
- throw new Error('Either oxyServices or baseURL must be provided to OxyContextProvider');
84
+ throw new Error('Either oxyServices or baseURL must be provided to OxyProvider');
67
85
  }
68
86
  }
69
87
  const oxyServices = oxyServicesRef.current;
70
88
 
71
- // The device-first persisted auth-state store (per-origin zero-cookie device
72
- // credential on web; SecureStore session blob on native). Built ONCE per
73
- // provider mount.
89
+ // The device-first persisted auth-state store (per-origin device credential on
90
+ // web; SecureStore session blob on native). Built ONCE per provider mount.
91
+ //
92
+ // `deviceCredentialStorage` is mount-time configuration for the same reason
93
+ // `sessionMode` is: it decides where the durable credential lives, and letting
94
+ // it change mid-flight would mean a session that started ephemeral could begin
95
+ // writing one.
74
96
  const authStoreRef = useRef(null);
75
97
  if (!authStoreRef.current) {
76
- authStoreRef.current = createPlatformAuthStateStore();
98
+ authStoreRef.current = createPlatformAuthStateStore({
99
+ sessionMode,
100
+ storage: deviceCredentialStorage
101
+ });
77
102
  }
78
103
  const authStore = authStoreRef.current;
79
104
 
@@ -93,34 +118,92 @@ export const OxyProvider = ({
93
118
  }
94
119
  const identity = identityRef.current;
95
120
  const isIdentityBound = identity !== null;
121
+ const logger = useCallback((message, err) => {
122
+ if (__DEV__) {
123
+ loggerUtil.warn(message, {
124
+ component: 'OxyContext'
125
+ }, err);
126
+ }
127
+ }, []);
128
+
129
+ // Server-authoritative device session client. Built ONCE per `oxyServices`
130
+ // instance. Device-scoped sockets connect with deviceId+deviceSecret when no
131
+ // bearer is planted yet, so cross-origin apps sync via `session_state`.
132
+ const sessionClientPairRef = useRef(null);
133
+ if (!sessionClientPairRef.current) {
134
+ sessionClientPairRef.current = createSessionClient(oxyServices, origin => {
135
+ // Erase the DURABLE device credential only on a `request`-origin verdict
136
+ // (a REST sign-out / revocation). A `push`-origin empty state is a socket
137
+ // broadcast that may be a transient reconnect artifact — clearing the
138
+ // credential on it would strand the user signed out with no way back, so
139
+ // we clear only the local UI session and keep the credential (a dead one
140
+ // re-mints to `no_active_session` and resolves signed-out on next boot).
141
+ if (origin === 'request') {
142
+ clearPersistedAuthSafe(authStore, logger);
143
+ }
144
+ void clearSessionStateRef.current().catch(clearError => {
145
+ logger('Failed to clear local state on remote sign-out', clearError);
146
+ });
147
+ },
148
+ // `null` for every account-mode provider — identical to omitting the
149
+ // option — and the pinned account id once an identity-bound provider has
150
+ // resolved its pin. Read through the ref so the resolver stays stable for
151
+ // the client's lifetime while still seeing later resolutions.
152
+ () => identityRef.current?.getPinnedAccountId() ?? null);
153
+ }
96
154
  const {
97
- user,
98
- isAuthenticated,
155
+ client: sessionClient,
156
+ host: sessionClientHost
157
+ } = sessionClientPairRef.current;
158
+
159
+ // ── The runtime ──────────────────────────────────────────────────────────
160
+ // One owner for the session facts (ADR 0004), built ONCE and never rebuilt,
161
+ // so the context value below can hand out a reference that never changes.
162
+ //
163
+ // Its three callbacks reach forward through refs because the collaborators
164
+ // they need — the storage-backed teardown, the account-graph refresh — are
165
+ // hooks declared after it. Latching the runtime here rather than after them
166
+ // is deliberate: a runtime rebuilt mid-flight would drop its `SessionClient`
167
+ // subscription and every subscriber with it.
168
+ const clearSessionStateRef = useRef(() => Promise.resolve());
169
+ const saveSessionIdsRef = useRef(() => undefined);
170
+ const subjectChangeRef = useRef(() => undefined);
171
+ const reestablishRef = useRef(() => undefined);
172
+ const runtimeRef = useRef(null);
173
+ if (!runtimeRef.current) {
174
+ runtimeRef.current = createOxyRuntime({
175
+ oxyServices,
176
+ sessionClient,
177
+ sessionClientHost,
178
+ identity,
179
+ onSubjectChange: transition => subjectChangeRef.current(transition),
180
+ onDeviceEmpty: () => clearSessionStateRef.current(),
181
+ onSessionsProjected: sessionIds => saveSessionIdsRef.current(sessionIds),
182
+ onIdentityUnbound: (binding, revision) => reestablishRef.current(binding, revision),
183
+ logger
184
+ });
185
+ }
186
+ const runtime = runtimeRef.current;
187
+ const snapshot = useRuntimeSnapshot(runtime);
188
+ const {
189
+ account: user,
190
+ sessions,
191
+ activeSessionId,
99
192
  isLoading,
100
- error,
101
- loginSuccess,
102
- loginFailure,
103
- logoutStore
104
- } = useAuthStore(useShallow(state => ({
105
- user: state.user,
106
- isAuthenticated: state.isAuthenticated,
107
- isLoading: state.isLoading,
108
- error: state.error,
109
- loginSuccess: state.loginSuccess,
110
- loginFailure: state.loginFailure,
111
- logoutStore: state.logout
112
- })));
113
- const [tokenReady, setTokenReady] = useState(true);
114
- const [hasAccessToken, setHasAccessToken] = useState(() => Boolean(oxyServices.getAccessToken()));
115
- const [authResolved, setAuthResolved] = useState(false);
116
- const authResolvedRef = useRef(false);
117
- const userRef = useRef(user);
118
- const isAuthenticatedRef = useRef(isAuthenticated);
119
- userRef.current = user;
120
- isAuthenticatedRef.current = isAuthenticated;
193
+ tokenReady,
194
+ hasAccessToken,
195
+ authResolved
196
+ } = snapshot;
197
+ const isAuthenticated = user !== null;
198
+ const error = snapshot.error?.message ?? null;
121
199
  const [initialized, setInitialized] = useState(false);
122
200
  const [accountDialogOpen, setAccountDialogOpen] = useState(false);
123
- const setAuthState = useAuthStore.setState;
201
+
202
+ // Project the runtime onto `useAuthStore`, which a dozen out-of-band callers
203
+ // (mutation success handlers, cache helpers, the Commons app) still read the
204
+ // signed-in user through. It is a projection, not a second store.
205
+ useEffect(() => bindAuthStoreToRuntime(runtime), [runtime]);
206
+ useEffect(() => runtime.start(), [runtime]);
124
207
 
125
208
  // Keep the shared `oxyClient` singleton's token store in lockstep with the
126
209
  // session owned by THIS provider's instance (many apps build API clients
@@ -140,13 +223,6 @@ export const OxyProvider = ({
140
223
  applyToSingleton(oxyServices.getAccessToken());
141
224
  return oxyServices.onTokensChanged(applyToSingleton);
142
225
  }, [oxyServices]);
143
- const logger = useCallback((message, err) => {
144
- if (__DEV__) {
145
- loggerUtil.warn(message, {
146
- component: 'OxyContext'
147
- }, err);
148
- }
149
- }, []);
150
226
  const storageKeys = useMemo(() => getStorageKeys(storageKeyPrefix), [storageKeyPrefix]);
151
227
  const clientId = useMemo(() => {
152
228
  const trimmed = clientIdProp?.trim();
@@ -180,6 +256,7 @@ export const OxyProvider = ({
180
256
  storageReady.resolve(storageInstance);
181
257
  if (mounted) {
182
258
  setStorage(storageInstance);
259
+ runtime.setStorageReady(true);
183
260
  }
184
261
  }).catch(err => {
185
262
  if (mounted) {
@@ -194,7 +271,7 @@ export const OxyProvider = ({
194
271
  return () => {
195
272
  mounted = false;
196
273
  };
197
- }, [logger, onError, storageReady]);
274
+ }, [logger, onError, runtime, storageReady]);
198
275
  const {
199
276
  currentLanguage,
200
277
  languages: currentLanguages,
@@ -211,85 +288,36 @@ export const OxyProvider = ({
211
288
  });
212
289
  const queryClient = useQueryClient();
213
290
  const {
214
- sessions,
215
- activeSessionId,
216
- setActiveSessionId,
217
- updateSessions,
291
+ saveSessionIds,
218
292
  switchSession,
219
293
  clearSessionState,
220
294
  saveActiveSessionId
221
295
  } = useSessionManagement({
222
296
  oxyServices,
297
+ runtime,
223
298
  storage,
224
299
  storageKeyPrefix,
225
- loginSuccess,
226
- logoutStore,
227
300
  onAuthStateChange,
228
301
  onError,
229
- setAuthError: message => setAuthState({
230
- error: message
231
- }),
302
+ setAuthError: message => runtime.setError(message),
232
303
  logger,
233
- setTokenReady,
234
304
  queryClient
235
305
  });
236
-
237
- // Refs so callbacks below can invoke the latest session-management functions
238
- // without widening dependency arrays.
239
- const switchSessionRef = useRef(switchSession);
240
- switchSessionRef.current = switchSession;
241
- const clearSessionStateRef = useRef(clearSessionState);
242
306
  clearSessionStateRef.current = clearSessionState;
243
- const setActiveSessionIdRef = useRef(setActiveSessionId);
244
- setActiveSessionIdRef.current = setActiveSessionId;
245
- const loginSuccessRef = useRef(loginSuccess);
246
- loginSuccessRef.current = loginSuccess;
307
+ saveSessionIdsRef.current = saveSessionIds;
247
308
  const onAuthStateChangeRef = useRef(onAuthStateChange);
248
309
  onAuthStateChangeRef.current = onAuthStateChange;
249
310
 
250
- // Flip the auth-resolution gate (`authResolved` + `tokenReady`) the moment a
251
- // session commits or the boot concludes signed out. Idempotent + monotonic.
311
+ // Flip the auth-resolution gate the moment a session commits or the boot
312
+ // concludes signed out. Idempotent + monotonic, enforced by the runtime.
252
313
  const markAuthResolved = useCallback(() => {
253
- if (authResolvedRef.current) {
254
- return;
255
- }
256
- authResolvedRef.current = true;
257
- setTokenReady(true);
258
- setAuthResolved(true);
259
- }, []);
314
+ runtime.markAuthResolved();
315
+ }, [runtime]);
260
316
  const markAuthResolvedRef = useRef(markAuthResolved);
261
317
  markAuthResolvedRef.current = markAuthResolved;
262
-
263
- // Server-authoritative device session client. Built ONCE per `oxyServices`
264
- // instance. Device-scoped sockets connect with deviceId+deviceSecret when no
265
- // bearer is planted yet, so cross-origin apps sync via `session_state` after
266
- // the one-shot join redirect.
267
- const sessionClientPairRef = useRef(null);
268
- if (!sessionClientPairRef.current) {
269
- sessionClientPairRef.current = createSessionClient(oxyServices, origin => {
270
- // Erase the DURABLE device credential only on a `request`-origin verdict
271
- // (a REST sign-out / revocation). A `push`-origin empty state is a socket
272
- // broadcast that may be a transient reconnect artifact — clearing the
273
- // credential on it would strand the user signed out with no way back, so
274
- // we clear only the local UI session and keep the credential (a dead one
275
- // re-mints to `no_active_session` and resolves signed-out on next boot).
276
- if (origin === 'request') {
277
- clearPersistedAuthSafe(authStore, logger);
278
- }
279
- void clearSessionStateRef.current().catch(clearError => {
280
- logger('Failed to clear local state on remote sign-out', clearError);
281
- });
282
- },
283
- // `null` for every account-mode provider — identical to omitting the
284
- // option — and the pinned account id once an identity-bound provider has
285
- // resolved its pin. Read through the ref so the resolver stays stable for
286
- // the client's lifetime while still seeing later resolutions.
287
- () => identityRef.current?.getPinnedAccountId() ?? null);
288
- }
289
- const {
290
- client: sessionClient,
291
- host: sessionClientHost
292
- } = sessionClientPairRef.current;
318
+ const setTokenReady = useCallback(ready => {
319
+ runtime.setTokenReady(ready);
320
+ }, [runtime]);
293
321
 
294
322
  // Re-establishment lane for an identity-bound provider whose pin is missing or
295
323
  // whose pinned account is no longer part of this device's session set (another
@@ -334,78 +362,22 @@ export const OxyProvider = ({
334
362
  tracker.inFlight = false;
335
363
  });
336
364
  }, [oxyServices, authStore, sessionClient, logger]);
365
+ reestablishRef.current = reestablishIdentitySession;
337
366
 
338
- // Projects `client.getState()` onto the exposed `sessions`/`activeSessionId`/
339
- // `user`. Sole authority for both locally-initiated mutations (switch/logout)
340
- // AND remotely-pushed `session_state` over the `device:<deviceId>` socket.
341
- const syncFromClient = useCallback(async () => {
342
- const state = sessionClient.getState();
343
- if (state === null) {
344
- return;
345
- }
346
- if (state.accounts.length === 0) {
347
- // Clear the LOCAL UI session on any applied empty state, but NEVER the
348
- // durable device credential here: `syncFromClient` runs for socket-pushed
349
- // (possibly transient) states too, and wiping the credential on one would
350
- // strand the user signed out. The credential wipe is gated on a
351
- // `request`-origin verdict in `onUnauthenticated` above.
352
- sessionClientHost.setCurrentAccountId(null);
353
- await clearSessionState();
354
- return;
355
- }
356
- // Last-write-wins guard: capture the revision this projection is for, then
357
- // after the async profile fetch bail if a fresher state has landed.
358
- const capturedRevision = state.revision;
359
- // Resolve the pin BEFORE the profile fetch (memoised: one storage + keychain
360
- // read per boot) so every projection below is bound on the FIRST pass over a
361
- // freshly applied state. Deferring it would let a sibling app's switch render
362
- // once as this client's user before the pin corrected it. `null` for every
363
- // account-mode provider, where each projection falls back to the device's
364
- // active account exactly as before.
365
- const pinnedAccountId = identity ? await identity.ensurePinnedAccountId() : null;
366
- const ids = accountIdsOf(state);
367
- let users = [];
368
- try {
369
- users = ids.length > 0 ? await oxyServices.getUsersByIds(ids) : [];
370
- } catch (fetchError) {
371
- logger('Failed to resolve account profiles during syncFromClient', fetchError);
372
- return;
373
- }
374
- const latest = sessionClient.getState();
375
- if (!latest || latest.revision !== capturedRevision) {
376
- return;
377
- }
378
- if (identity && (pinnedAccountId === null || activeSessionIdOf(latest, pinnedAccountId) === null)) {
379
- // Either no verified pin, or the pinned account left this device's session
380
- // set. Projecting anything here would mean projecting SOMEBODY ELSE's
381
- // account, so leave the current projection untouched and re-derive the
382
- // session from the local identity key instead.
383
- reestablishIdentitySession(identity, latest.revision);
384
- return;
385
- }
386
- const usersById = new Map(users.map(resolvedUser => [resolvedUser.id, resolvedUser]));
387
- updateSessions(deviceStateToClientSessions(latest, usersById, pinnedAccountId));
388
- setActiveSessionId(activeSessionIdOf(latest, pinnedAccountId));
389
- const activeUser = activeUserOf(latest, usersById, pinnedAccountId);
390
- if (activeUser) {
391
- loginSuccess(activeUser);
392
- }
393
- // The host's current account feeds the socket handshake and the bearer's
394
- // token-account comparisons, so it tracks the PIN — never the account another
395
- // app switched the device to.
396
- sessionClientHost.setCurrentAccountId(pinnedAccountId ?? latest.activeAccountId);
397
- }, [identity, oxyServices, reestablishIdentitySession, sessionClient, sessionClientHost, updateSessions, setActiveSessionId, loginSuccess, clearSessionState, logger]);
367
+ /**
368
+ * Project the server-authoritative device state onto the runtime.
369
+ *
370
+ * The projection itself lives in the runtime; this is the awaitable handle
371
+ * the commit/logout/reconnect paths already had. It is stable, because the
372
+ * runtime is.
373
+ */
374
+ const syncFromClient = useCallback(() => runtime.reconcileFromClient(), [runtime]);
398
375
  const syncFromClientRef = useRef(syncFromClient);
399
376
  syncFromClientRef.current = syncFromClient;
400
377
  const syncDeviceCredentialToHost = useCallback(async () => {
401
378
  const cred = await loadPersistedDeviceCredential(authStore);
402
379
  sessionClientHost.setDeviceCredential(cred);
403
380
  }, [authStore, sessionClientHost]);
404
- useEffect(() => {
405
- return sessionClient.subscribe(() => {
406
- void syncFromClient();
407
- });
408
- }, [sessionClient, syncFromClient]);
409
381
  const {
410
382
  signIn,
411
383
  logout,
@@ -414,9 +386,7 @@ export const OxyProvider = ({
414
386
  oxyServices,
415
387
  store: authStore,
416
388
  storage,
417
- activeSessionId,
418
- setActiveSessionId,
419
- updateSessions,
389
+ runtime,
420
390
  saveActiveSessionId,
421
391
  clearSessionState,
422
392
  switchSession,
@@ -424,10 +394,6 @@ export const OxyProvider = ({
424
394
  syncFromClient,
425
395
  onAuthStateChange,
426
396
  onError,
427
- loginSuccess,
428
- loginFailure,
429
- logoutStore,
430
- setAuthState,
431
397
  logger,
432
398
  ...(identity ? {
433
399
  identityBinding: identity.binding,
@@ -456,7 +422,6 @@ export const OxyProvider = ({
456
422
  // Explicit FULL wipe: also drop the persisted device credential so a reload
457
423
  // finds nothing to restore.
458
424
  await authStore.clear();
459
- useAccountStore.getState().reset();
460
425
  oxyServices.clearCache();
461
426
  }, [queryClient, storage, clearSessionState, authStore, logger, oxyServices]);
462
427
  const {
@@ -470,7 +435,6 @@ export const OxyProvider = ({
470
435
  clearSessionState,
471
436
  logger
472
437
  });
473
- const useFollowHook = loadUseFollowHook();
474
438
 
475
439
  // Token-change side effects: an invalidated bearer (HttpService clears tokens
476
440
  // on an unrecoverable 401 and emits `null`) must locally sign out an
@@ -481,16 +445,16 @@ export const OxyProvider = ({
481
445
  const clearingInvalidTokenRef = useRef(false);
482
446
  useEffect(() => {
483
447
  const handleTokenChange = accessToken => {
484
- setHasAccessToken(Boolean(accessToken));
448
+ runtime.setHasAccessToken(Boolean(accessToken));
485
449
  if (accessToken) {
486
- setTokenReady(true);
450
+ runtime.setTokenReady(true);
487
451
  if (sessionClient.getState()?.accounts.length) {
488
452
  void syncFromClientRef.current();
489
453
  }
490
454
  return;
491
455
  }
492
- if (userRef.current || isAuthenticatedRef.current) {
493
- setTokenReady(false);
456
+ if (runtime.getSnapshot().account !== null) {
457
+ runtime.setTokenReady(false);
494
458
  if (clearingInvalidTokenRef.current) {
495
459
  return;
496
460
  }
@@ -499,19 +463,19 @@ export const OxyProvider = ({
499
463
  logger('Failed to clear invalidated auth session', clearError);
500
464
  }).finally(() => {
501
465
  clearingInvalidTokenRef.current = false;
502
- if (authResolvedRef.current) {
503
- setTokenReady(true);
466
+ if (runtime.getSnapshot().authResolved) {
467
+ runtime.setTokenReady(true);
504
468
  }
505
469
  });
506
470
  return;
507
471
  }
508
- if (authResolvedRef.current) {
509
- setTokenReady(true);
472
+ if (runtime.getSnapshot().authResolved) {
473
+ runtime.setTokenReady(true);
510
474
  }
511
475
  };
512
476
  handleTokenChange(oxyServices.getAccessToken());
513
477
  return oxyServices.onTokensChanged(handleTokenChange);
514
- }, [logger, oxyServices, sessionClient]);
478
+ }, [logger, oxyServices, runtime, sessionClient]);
515
479
 
516
480
  // Unified in-session refresh (SDK-owned; every RP inherits it). Installs the
517
481
  // ONE core refresh handler (re-mint from the persisted zero-cookie device
@@ -574,20 +538,25 @@ export const OxyProvider = ({
574
538
  }
575
539
 
576
540
  // Fast local mirror so the UI updates before the server round-trip; the
577
- // SessionClient projection below overwrites it with server truth.
541
+ // SessionClient projection below overwrites it with server truth. Batched
542
+ // so the mirror and the active id land in ONE transition — unbatched, a
543
+ // subscriber woken between them would see the new session list still
544
+ // pointing at the previous active id.
578
545
  if (input.userId) {
579
546
  const now = new Date();
580
- updateSessions([{
581
- sessionId: input.sessionId,
582
- deviceId: input.deviceId ?? '',
583
- expiresAt: input.expiresAt || new Date(now.getTime() + DEFAULT_SESSION_VALIDITY_MS).toISOString(),
584
- lastActive: now.toISOString(),
585
- userId: input.userId,
586
- isCurrent: true
587
- }], {
588
- merge: true
547
+ runtime.batch(() => {
548
+ runtime.mergeSessions([{
549
+ sessionId: input.sessionId,
550
+ deviceId: input.deviceId ?? '',
551
+ expiresAt: input.expiresAt || new Date(now.getTime() + DEFAULT_SESSION_VALIDITY_MS).toISOString(),
552
+ lastActive: now.toISOString(),
553
+ userId: input.userId,
554
+ isCurrent: true
555
+ }], {
556
+ merge: true
557
+ });
558
+ runtime.setActiveSessionId(input.sessionId);
589
559
  });
590
- setActiveSessionId(input.sessionId);
591
560
  }
592
561
 
593
562
  // Register into the device set, hydrate the full user, and flip the
@@ -607,11 +576,11 @@ export const OxyProvider = ({
607
576
  startSocket: () => sessionClient.start(),
608
577
  syncFromClient,
609
578
  getCurrentUser: () => oxyServices.getCurrentUser(),
610
- loginSuccess,
579
+ loginSuccess: fullUser => runtime.setAccount(fullUser),
611
580
  onAuthStateChange: onAuthStateChangeRef.current,
612
581
  markAuthResolved: markAuthResolvedRef.current
613
582
  });
614
- }, [oxyServices, authStore, updateSessions, setActiveSessionId, sessionClient, sessionClientHost, syncFromClient, loginSuccess, logger]);
583
+ }, [oxyServices, authStore, runtime, sessionClient, sessionClientHost, syncFromClient, logger]);
615
584
  const commitSessionRef = useRef(commitSession);
616
585
  commitSessionRef.current = commitSession;
617
586
 
@@ -634,27 +603,6 @@ export const OxyProvider = ({
634
603
  });
635
604
  }, [commitSession]);
636
605
 
637
- // Commit a minted graph-SWITCH session through the same funnel as
638
- // `handleWebSession`. Nothing extra to do IN-PLACE: the switch already
639
- // propagates across tabs/apps via the server's `session_state` socket
640
- // broadcast.
641
- const commitSwitchedSession = useCallback(async session => {
642
- if (!session?.user || !session?.sessionId || !session.accessToken) {
643
- throw new Error('Session response did not include a usable session');
644
- }
645
- await commitSession({
646
- sessionId: session.sessionId,
647
- accessToken: session.accessToken,
648
- deviceSecret: session.deviceSecret,
649
- deviceId: session.deviceId,
650
- expiresAt: session.expiresAt,
651
- userId: session.user.id,
652
- user: session.user
653
- }, {
654
- activate: true
655
- });
656
- }, [commitSession]);
657
-
658
606
  // ── Web third-party OAuth sign-in ──────────────────────────────────────────
659
607
  // The shared operation `OxySignInButton` (and any RP-owned button) delegates
660
608
  // to, so no consumer ever writes popup listeners or a token exchange. The
@@ -674,13 +622,11 @@ export const OxyProvider = ({
674
622
  // ── Unified account dialog ─────────────────────────────────────────────────
675
623
  // The single account-chooser + sign-in surface. Built ONCE per provider mount
676
624
  // and bound to the live `oxyServices` + `sessionClient` + this provider's
677
- // commit funnels. Both funnels are threaded through refs so the controller
678
- // keeps STABLE commit callbacks (rebuilding the controller on every
679
- // commit-identity change would drop its subscription + state).
625
+ // sign-in commit funnel, threaded through a ref so the controller keeps a
626
+ // STABLE commit callback (rebuilding the controller on every commit-identity
627
+ // change would drop its subscription + state).
680
628
  const handleWebSessionRef = useRef(handleWebSession);
681
629
  handleWebSessionRef.current = handleWebSession;
682
- const commitSwitchedSessionRef = useRef(commitSwitchedSession);
683
- commitSwitchedSessionRef.current = commitSwitchedSession;
684
630
 
685
631
  // The live AccountDialog surface (a stacked Bloom surface), while open — the
686
632
  // SINGLE source of truth for "is the account dialog open". Held so
@@ -723,12 +669,10 @@ export const OxyProvider = ({
723
669
  oxyServices,
724
670
  sessionClient,
725
671
  clientId,
726
- locale: currentLanguage,
727
672
  // Same statically-injected `io` as the SessionClient: gives the QR flow an
728
673
  // instant `/auth-session` `auth_update` wake instead of a slow poll.
729
674
  socketFactory: io,
730
675
  commitSession: session => handleWebSessionRef.current(session),
731
- commitSwitchedSession: session => commitSwitchedSessionRef.current(session),
732
676
  onSignedIn: () => {
733
677
  // Close the dialog: pop the morphed frame back to its host surface, or
734
678
  // dismiss the detached surface (whose settle flips `accountDialogOpen`).
@@ -947,7 +891,7 @@ export const OxyProvider = ({
947
891
  if (identity) {
948
892
  await identity.refreshPinnedAccountId();
949
893
  }
950
- }, [oxyServices, authStore, clientIdProp, authRedirectUri, sessionMode, identity, syncDeviceCredentialToHost, sessionClient]);
894
+ }, [oxyServices, authStore, clientIdProp, authRedirectUri, sessionMode, identity, syncDeviceCredentialToHost, sessionClient, setTokenReady]);
951
895
  useEffect(() => {
952
896
  if (initialized) {
953
897
  return;
@@ -1046,12 +990,12 @@ export const OxyProvider = ({
1046
990
  }
1047
991
  await sessionClient.switchAccount(targetAccountId);
1048
992
  await syncFromClient();
1049
- const activeUser = useAuthStore.getState().user;
993
+ const activeUser = runtime.getSnapshot().account;
1050
994
  if (!activeUser) {
1051
995
  throw new Error('Active account profile could not be resolved after switch');
1052
996
  }
1053
997
  return activeUser;
1054
- }, [isIdentityBound, sessionClient, syncFromClient]);
998
+ }, [isIdentityBound, runtime, sessionClient, syncFromClient]);
1055
999
 
1056
1000
  // Thin passthroughs to the platform-agnostic KeyManager. NOTE: both now THROW
1057
1001
  // `IdentityUnavailableError` (from `@oxyhq/core`) when identity storage is
@@ -1087,10 +1031,44 @@ export const OxyProvider = ({
1087
1031
  sessionClient,
1088
1032
  syncFromClient,
1089
1033
  commitSession,
1090
- queryClient,
1091
1034
  accountDialogControllerRef,
1092
1035
  clearSessionStateRef
1093
1036
  });
1037
+
1038
+ // The account-scoped cache reset, run by the runtime BETWEEN committing the
1039
+ // new subject's bearer and waking anybody (ADR 0002). It used to trail the two
1040
+ // branches of `switchToAccount`, which meant a switch pushed over the socket
1041
+ // by another app on this device got none of it: the follow stores, the scoped
1042
+ // media URLs and every warm query stayed on the previous subject until
1043
+ // something happened to refetch.
1044
+ //
1045
+ // An initial sign-in is deliberately exempt. There is nothing account-scoped
1046
+ // cached before the first account, so invalidating everything there would only
1047
+ // buy a refetch storm at first paint.
1048
+ const handleSubjectChange = useCallback(({
1049
+ previous,
1050
+ next
1051
+ }) => {
1052
+ if (previous === null) {
1053
+ return;
1054
+ }
1055
+ resetSessionScopedStores();
1056
+ if (next === null) {
1057
+ // A sign-out: `clearSessionState` owns the rest of the teardown, and
1058
+ // invalidating a cache we are about to clear would only refetch as the
1059
+ // bearer disappears.
1060
+ return;
1061
+ }
1062
+ // Scoped media tokens are per-viewer — drop any cached URLs immediately so
1063
+ // `keepPreviousData`-style placeholders cannot flash the prior account's
1064
+ // private thumbnails while the new bearer mint lands.
1065
+ queryClient.removeQueries({
1066
+ queryKey: [ASSET_DOWNLOAD_URLS_QUERY_KEY]
1067
+ });
1068
+ queryClient.invalidateQueries();
1069
+ void refreshAccounts();
1070
+ }, [queryClient, refreshAccounts]);
1071
+ subjectChangeRef.current = handleSubjectChange;
1094
1072
  const canUsePrivateApi = authResolved && isAuthenticated && tokenReady && hasAccessToken;
1095
1073
  const isPrivateApiPending = !authResolved || isAuthenticated && (!tokenReady || !hasAccessToken);
1096
1074
 
@@ -1116,7 +1094,7 @@ export const OxyProvider = ({
1116
1094
  canUsePrivateApi,
1117
1095
  isPrivateApiPending,
1118
1096
  isAuthResolved: authResolved,
1119
- isStorageReady: storage !== null,
1097
+ isStorageReady: snapshot.storageReady,
1120
1098
  sessionMode: isIdentityBound ? 'identity' : 'account',
1121
1099
  webAuthMode,
1122
1100
  error,
@@ -1150,7 +1128,7 @@ export const OxyProvider = ({
1150
1128
  clientId,
1151
1129
  oxyServices,
1152
1130
  sessionClient,
1153
- useFollow: useFollowHook,
1131
+ useFollow,
1154
1132
  showBottomSheet: showBottomSheetForContext,
1155
1133
  openAvatarPicker,
1156
1134
  accountDialogController,
@@ -1161,83 +1139,53 @@ export const OxyProvider = ({
1161
1139
  switchToAccount,
1162
1140
  refreshAccounts,
1163
1141
  createAccount: createAccountFn
1164
- }), [user, sessions, activeSessionId, isAuthenticated, isLoading, tokenReady, hasAccessToken, canUsePrivateApi, isPrivateApiPending, authResolved, storage, isIdentityBound, webAuthMode, error, currentLanguage, currentLanguages, currentLanguageMetadata, currentLanguageName, currentNativeLanguageName, hasIdentity, getPublicKey, signIn, signInWithPasskey, registerWithPasskey, addPasskey, removePasskey, revokeSuspiciousSignIn, handleWebSession, startWebOAuthSignInForContext, logout, logoutAll, switchSessionForContext, refreshSessionsForContext, setLanguage, getDeviceSessions, logoutAllDeviceSessions, updateDeviceName, clearSessionState, clearAllAccountData, storageKeyPrefix, clientId, oxyServices, sessionClient, useFollowHook, showBottomSheetForContext, openAvatarPicker, accountDialogController, accountDialogOpen, openAccountDialog, closeAccountDialog, accounts, switchToAccount, refreshAccounts, createAccountFn]);
1165
- return /*#__PURE__*/_jsx(OxyContext.Provider, {
1166
- value: contextValue,
1167
- children: children
1142
+ }), [user, sessions, activeSessionId, isAuthenticated, isLoading, tokenReady, hasAccessToken, canUsePrivateApi, isPrivateApiPending, authResolved, snapshot.storageReady, isIdentityBound, webAuthMode, error, currentLanguage, currentLanguages, currentLanguageMetadata, currentLanguageName, currentNativeLanguageName, hasIdentity, getPublicKey, signIn, signInWithPasskey, registerWithPasskey, addPasskey, removePasskey, revokeSuspiciousSignIn, handleWebSession, startWebOAuthSignInForContext, logout, logoutAll, switchSessionForContext, refreshSessionsForContext, setLanguage, getDeviceSessions, logoutAllDeviceSessions, updateDeviceName, clearSessionState, clearAllAccountData, storageKeyPrefix, clientId, oxyServices, sessionClient, showBottomSheetForContext, openAvatarPicker, accountDialogController, accountDialogOpen, openAccountDialog, closeAccountDialog, accounts, switchToAccount, refreshAccounts, createAccountFn]);
1143
+
1144
+ // Two contexts, deliberately. The inner one carries the wide compatibility
1145
+ // value every `useOxy()` consumer reads, rebuilt whenever any of its members
1146
+ // moves. The outer one carries the runtime reference, which never changes
1147
+ // identity — so `useActiveAccount()` and friends re-render on the fact they
1148
+ // selected and nothing else. Phase 8 retires the inner one.
1149
+ return /*#__PURE__*/_jsx(OxyRuntimeHandleProvider, {
1150
+ value: runtime,
1151
+ children: /*#__PURE__*/_jsx(OxyRuntimeContext.Provider, {
1152
+ value: contextValue,
1153
+ children: children
1154
+ })
1168
1155
  });
1169
1156
  };
1170
- export const OxyContextProvider = OxyProvider;
1157
+ const PROVIDER_MISSING_ERROR_MESSAGE = 'useOxy() was called outside <OxyProvider>. Mount <OxyProvider clientId="…"> above this component, ' + 'or use useOptionalOxy() if this component legitimately renders both inside and outside the provider.';
1158
+ export class OxyProviderMissingError extends Error {
1159
+ code = 'oxy_provider_missing';
1160
+ constructor() {
1161
+ super(PROVIDER_MISSING_ERROR_MESSAGE);
1162
+ this.name = 'OxyProviderMissingError';
1163
+ }
1164
+ }
1171
1165
 
1172
1166
  /**
1173
- * Loading-state stub used when `useOxy()` is called outside an OxyProvider.
1174
- * All async methods reject with a clear error so misuse is caught early.
1167
+ * The base runtime hook. THROWS when no `<OxyProvider>` is mounted.
1168
+ *
1169
+ * It used to return a fabricated forever-loading runtime — `isLoading: true`,
1170
+ * `isPrivateApiPending: true`, every method a rejecting no-op — which turned a
1171
+ * missing provider into a UI that spins forever with nothing in the console.
1172
+ * Failing here names the mistake at the exact component that made it (ADR 0004).
1173
+ *
1174
+ * A component that legitimately renders both inside and outside the provider
1175
+ * uses {@link useOptionalOxy} instead.
1175
1176
  */
1176
- const PROVIDER_MISSING_ERROR_MESSAGE = 'OxyProvider is not mounted. Wrap your app in <OxyProvider> before calling useOxy() methods.';
1177
- const rejectMissingProvider = () => Promise.reject(new Error(PROVIDER_MISSING_ERROR_MESSAGE));
1178
- const LOADING_STATE_OXY_SERVICES = new OxyServices({
1179
- baseURL: 'about:blank'
1180
- });
1181
- const LOADING_STATE = {
1182
- user: null,
1183
- sessions: [],
1184
- activeSessionId: null,
1185
- isAuthenticated: false,
1186
- isLoading: true,
1187
- isTokenReady: false,
1188
- hasAccessToken: false,
1189
- canUsePrivateApi: false,
1190
- isPrivateApiPending: true,
1191
- isAuthResolved: false,
1192
- isStorageReady: false,
1193
- sessionMode: 'account',
1194
- webAuthMode: 'popup',
1195
- error: null,
1196
- currentLanguage: 'en-US',
1197
- currentLanguages: [],
1198
- currentLanguageMetadata: null,
1199
- currentLanguageName: 'English (United States)',
1200
- currentNativeLanguageName: 'English (United States)',
1201
- hasIdentity: () => Promise.resolve(false),
1202
- getPublicKey: () => Promise.resolve(null),
1203
- signIn: () => rejectMissingProvider(),
1204
- signInWithPasskey: () => rejectMissingProvider(),
1205
- registerWithPasskey: () => rejectMissingProvider(),
1206
- addPasskey: () => rejectMissingProvider(),
1207
- removePasskey: () => rejectMissingProvider(),
1208
- revokeSuspiciousSignIn: () => rejectMissingProvider(),
1209
- handleWebSession: () => rejectMissingProvider(),
1210
- startWebOAuthSignIn: () => rejectMissingProvider(),
1211
- logout: () => rejectMissingProvider(),
1212
- logoutAll: () => rejectMissingProvider(),
1213
- switchSession: () => rejectMissingProvider(),
1214
- removeSession: () => rejectMissingProvider(),
1215
- refreshSessions: () => rejectMissingProvider(),
1216
- setLanguage: () => rejectMissingProvider(),
1217
- getDeviceSessions: () => Promise.resolve([]),
1218
- logoutAllDeviceSessions: () => rejectMissingProvider(),
1219
- updateDeviceName: () => rejectMissingProvider(),
1220
- clearSessionState: () => rejectMissingProvider(),
1221
- clearAllAccountData: () => rejectMissingProvider(),
1222
- storageKeyPrefix: 'oxy_session',
1223
- clientId: null,
1224
- oxyServices: LOADING_STATE_OXY_SERVICES,
1225
- sessionClient: null,
1226
- openAvatarPicker: () => {},
1227
- accountDialogController: null,
1228
- isAccountDialogOpen: false,
1229
- openAccountDialog: () => {},
1230
- closeAccountDialog: () => {},
1231
- accounts: [],
1232
- switchToAccount: () => rejectMissingProvider(),
1233
- refreshAccounts: () => rejectMissingProvider(),
1234
- createAccount: () => rejectMissingProvider()
1235
- };
1236
1177
  export const useOxy = () => {
1237
- const context = useContext(OxyContext);
1178
+ const context = useContext(OxyRuntimeContext);
1238
1179
  if (!context) {
1239
- return LOADING_STATE;
1180
+ throw new OxyProviderMissingError();
1240
1181
  }
1241
1182
  return context;
1242
1183
  };
1184
+
1185
+ /**
1186
+ * `useOxy()` for the rare component that renders both inside and outside the
1187
+ * provider — returns `null` instead of throwing. Callers must handle `null`;
1188
+ * there is no fabricated runtime to fall back on.
1189
+ */
1190
+ export const useOptionalOxy = () => useContext(OxyRuntimeContext);
1243
1191
  //# sourceMappingURL=OxyContext.js.map