@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
@@ -0,0 +1,289 @@
1
+ /**
2
+ * The platform half of the shared DeviceSession credential.
3
+ *
4
+ * `@oxyhq/core` owns and tests the RULES; what is pinned here is the mapping from
5
+ * each platform's failure shapes onto them — and that mapping is where the
6
+ * dangerous mistake lives. `expo-secure-store` returns `null` for a missing item
7
+ * and THROWS when the keychain refuses; the Android broker answers with an
8
+ * explicit status. Collapsing either failure into "absent" is what would let a
9
+ * locked device look like one that never had a session.
10
+ */
11
+ import type { SharedDeviceCredentialStore } from '@oxyhq/core';
12
+
13
+ const CRED = { deviceId: 'dev-shared', deviceSecret: 'ds-shared' };
14
+ const STORAGE_KEY = 'oxy_shared_device_session_v1';
15
+
16
+ /** A minimal in-memory `expo-secure-store` that records the options it was given. */
17
+ function makeSecureStoreMock() {
18
+ const items = new Map<string, string>();
19
+ const calls: { key: string; options?: Record<string, unknown> }[] = [];
20
+ let readError: Error | null = null;
21
+ let writeError: Error | null = null;
22
+ /** When set, `setItemAsync` resolves but nothing lands — the phantom-write case. */
23
+ let swallowWrites = false;
24
+ return {
25
+ items,
26
+ calls,
27
+ setReadError: (error: Error | null) => {
28
+ readError = error;
29
+ },
30
+ setWriteError: (error: Error | null) => {
31
+ writeError = error;
32
+ },
33
+ setSwallowWrites: (value: boolean) => {
34
+ swallowWrites = value;
35
+ },
36
+ module: {
37
+ WHEN_UNLOCKED_THIS_DEVICE_ONLY: 3,
38
+ getItemAsync: async (key: string, options?: Record<string, unknown>) => {
39
+ calls.push({ key, options });
40
+ if (readError) {
41
+ throw readError;
42
+ }
43
+ return items.get(key) ?? null;
44
+ },
45
+ setItemAsync: async (key: string, value: string, options?: Record<string, unknown>) => {
46
+ calls.push({ key, options });
47
+ if (writeError) {
48
+ throw writeError;
49
+ }
50
+ if (!swallowWrites) {
51
+ items.set(key, value);
52
+ }
53
+ },
54
+ deleteItemAsync: async (key: string, options?: Record<string, unknown>) => {
55
+ calls.push({ key, options });
56
+ items.delete(key);
57
+ },
58
+ },
59
+ };
60
+ }
61
+
62
+ type BrokerModule = {
63
+ read(): Promise<unknown>;
64
+ write(deviceId: string, deviceSecret: string): Promise<boolean>;
65
+ clear(): Promise<void>;
66
+ };
67
+
68
+ /**
69
+ * Load the module fresh, with `Platform.OS` set and both native seams mocked.
70
+ *
71
+ * Two things here are load-bearing and were each got wrong first:
72
+ *
73
+ * - `jest.resetModules()` + `require`, NOT `jest.isolateModules`. The module
74
+ * memoises its keychain and broker handles at module scope, so it must be
75
+ * re-required per case — and with `isolateModules` a mock factory registered
76
+ * in one block leaked into the next block's module, so a test's own mock was
77
+ * silently ignored and its assertions read the PREVIOUS test's store.
78
+ * - `Platform.OS` is set on the instance in the CURRENT registry. A reset hands
79
+ * out a fresh `react-native` mock whose `OS` is back to its `'web'` default,
80
+ * so mutating an instance captured earlier leaves the code under test on the
81
+ * web branch and every platform assertion passes vacuously.
82
+ */
83
+ function loadStore(
84
+ os: 'ios' | 'android' | 'web',
85
+ seams: { secureStore?: ReturnType<typeof makeSecureStoreMock>; broker?: BrokerModule | null } = {},
86
+ ): SharedDeviceCredentialStore | null {
87
+ jest.resetModules();
88
+ jest.doMock('expo-modules-core', () => ({
89
+ requireOptionalNativeModule: () => seams.broker ?? null,
90
+ requireNativeModule: () => {
91
+ throw new Error('not available');
92
+ },
93
+ }));
94
+ // NOT `{ virtual: true }`: a virtual mock is keyed to the directory of the
95
+ // file that declared it, so one declared here would be invisible to the module
96
+ // under test two directories up — it would silently keep resolving
97
+ // `unsupported`. `expo-secure-store` is installed in the workspace, so the
98
+ // ordinary mock registers against its real resolved path. With no mock given,
99
+ // model the module being ABSENT.
100
+ const secureStoreModule = seams.secureStore?.module;
101
+ jest.doMock('expo-secure-store', () => {
102
+ if (!secureStoreModule) {
103
+ throw new Error("Cannot find module 'expo-secure-store'");
104
+ }
105
+ return secureStoreModule;
106
+ });
107
+ const rn = require('react-native') as { Platform: { OS: string } };
108
+ rn.Platform.OS = os;
109
+ const mod = require('../sharedDeviceCredentialStore') as typeof import('../sharedDeviceCredentialStore');
110
+ return mod.createPlatformSharedDeviceCredentialStore();
111
+ }
112
+
113
+ afterEach(() => {
114
+ jest.dontMock('expo-modules-core');
115
+ jest.dontMock('expo-secure-store');
116
+ jest.resetModules();
117
+ });
118
+
119
+ describe('createPlatformSharedDeviceCredentialStore', () => {
120
+ test('web has no shared slot at all', () => {
121
+ // Each web origin is its own device by design; there is nothing to join.
122
+ expect(loadStore('web')).toBeNull();
123
+ // Positive control: `null` must mean "web", not "the harness never reached
124
+ // the platform branch" — the failure mode this whole harness had once.
125
+ expect(loadStore('android', { broker: null })).not.toBeNull();
126
+ expect(loadStore('ios')).not.toBeNull();
127
+ });
128
+
129
+ test('iOS uses the keychain, not the Android broker', async () => {
130
+ // The branch is on the platform because `expo-secure-store` LOADS on Android
131
+ // too — it would just ignore the access group and read a package-private
132
+ // item, which is indistinguishable from an empty shared slot.
133
+ const secureStore = makeSecureStoreMock();
134
+ const broker: BrokerModule = {
135
+ read: jest.fn(async () => ({ status: 'present', ...CRED })),
136
+ write: jest.fn(async () => true),
137
+ clear: jest.fn(async () => undefined),
138
+ };
139
+ const store = loadStore('ios', { secureStore, broker });
140
+ await store?.read();
141
+ expect(broker.read).not.toHaveBeenCalled();
142
+ expect(secureStore.calls.length).toBeGreaterThan(0);
143
+ });
144
+
145
+ test('Android uses the broker, not the keychain', async () => {
146
+ const secureStore = makeSecureStoreMock();
147
+ const broker: BrokerModule = {
148
+ read: jest.fn(async () => ({ status: 'absent' })),
149
+ write: jest.fn(async () => true),
150
+ clear: jest.fn(async () => undefined),
151
+ };
152
+ const store = loadStore('android', { secureStore, broker });
153
+ await expect(store?.read()).resolves.toEqual({ state: 'absent' });
154
+ expect(broker.read).toHaveBeenCalled();
155
+ expect(secureStore.calls).toHaveLength(0);
156
+ });
157
+ });
158
+
159
+ describe('iOS keychain-group slot', () => {
160
+ test('a missing item is absent; a THROWN read is unavailable', async () => {
161
+ const secureStore = makeSecureStoreMock();
162
+ const store = loadStore('ios', { secureStore });
163
+
164
+ await expect(store?.read()).resolves.toEqual({ state: 'absent' });
165
+
166
+ secureStore.setReadError(new Error('User interaction is not allowed'));
167
+ const locked = await store?.read();
168
+ // The pair that must never be confused. `absent` authorises seeding the slot.
169
+ expect(locked?.state).toBe('unavailable');
170
+ });
171
+
172
+ test('an unparseable item is unavailable, never absent', async () => {
173
+ const secureStore = makeSecureStoreMock();
174
+ secureStore.items.set(STORAGE_KEY, 'not-json-at-all');
175
+ const store = loadStore('ios', { secureStore });
176
+ // Something IS stored. Reporting absent would authorise overwriting whatever
177
+ // a newer build put there.
178
+ expect((await store?.read())?.state).toBe('unavailable');
179
+ });
180
+
181
+ test('reads and writes carry the dedicated service AND the access group', async () => {
182
+ const secureStore = makeSecureStoreMock();
183
+ const store = loadStore('ios', { secureStore });
184
+ await store?.publish(CRED);
185
+
186
+ // Without `keychainAccessGroup` the item is package-private and no sibling
187
+ // app can ever join. Without the dedicated `keychainService` it shares the
188
+ // legacy shared-IDENTITY namespace inside the group — the exact conflation
189
+ // this phase exists to end.
190
+ for (const call of secureStore.calls) {
191
+ expect(call.options).toMatchObject({
192
+ keychainService: 'oxy_device_session',
193
+ keychainAccessGroup: 'group.so.oxy.shared',
194
+ });
195
+ }
196
+ expect(secureStore.calls.length).toBeGreaterThan(0);
197
+ });
198
+
199
+ test('the item is written device-only so it never rides an OS backup to a new handset', async () => {
200
+ const secureStore = makeSecureStoreMock();
201
+ const store = loadStore('ios', { secureStore });
202
+ await store?.publish(CRED);
203
+ const write = secureStore.calls.find((c) => c.options?.keychainAccessible !== undefined);
204
+ expect(write?.options?.keychainAccessible).toBe(secureStore.module.WHEN_UNLOCKED_THIS_DEVICE_ONLY);
205
+ });
206
+
207
+ test('a publish round-trips and reads back as present', async () => {
208
+ const secureStore = makeSecureStoreMock();
209
+ const store = loadStore('ios', { secureStore });
210
+ await expect(store?.publish(CRED)).resolves.toBe(true);
211
+ await expect(store?.read()).resolves.toEqual({ state: 'present', credential: CRED });
212
+ });
213
+
214
+ test('a write that silently does not land reports false', async () => {
215
+ // A keychain write can resolve without the item landing under the access
216
+ // group (a missing entitlement is the usual cause). A phantom credential
217
+ // would send a fresh install into a mint that can never succeed.
218
+ const secureStore = makeSecureStoreMock();
219
+ secureStore.setSwallowWrites(true);
220
+ const store = loadStore('ios', { secureStore });
221
+ await expect(store?.publish(CRED)).resolves.toBe(false);
222
+ });
223
+
224
+ test('a throwing write reports false rather than propagating', async () => {
225
+ const secureStore = makeSecureStoreMock();
226
+ secureStore.setWriteError(new Error('keychain error -34018'));
227
+ const store = loadStore('ios', { secureStore });
228
+ await expect(store?.publish(CRED)).resolves.toBe(false);
229
+ });
230
+
231
+ test('the slot is unsupported when expo-secure-store is not installed', async () => {
232
+ const store = loadStore('ios');
233
+ // No `expo-secure-store` mock registered → the dynamic import rejects.
234
+ expect((await store?.read())?.state).toBe('unsupported');
235
+ });
236
+ });
237
+
238
+ describe('Android broker slot', () => {
239
+ test('narrows a present payload', async () => {
240
+ const store = loadStore('android', {
241
+ broker: { read: async () => ({ status: 'present', ...CRED }), write: async () => true, clear: async () => undefined },
242
+ });
243
+ await expect(store?.read()).resolves.toEqual({ state: 'present', credential: CRED });
244
+ });
245
+
246
+ test('an explicit unavailable status stays unavailable', async () => {
247
+ const store = loadStore('android', {
248
+ broker: {
249
+ read: async () => ({ status: 'unavailable', reason: 'GeneralSecurityException' }),
250
+ write: async () => true,
251
+ clear: async () => undefined,
252
+ },
253
+ });
254
+ expect((await store?.read())?.state).toBe('unavailable');
255
+ });
256
+
257
+ test('a THROWN broker call is unavailable, never absent', async () => {
258
+ const store = loadStore('android', {
259
+ broker: {
260
+ read: async () => {
261
+ throw new Error('binder transaction failed');
262
+ },
263
+ write: async () => true,
264
+ clear: async () => undefined,
265
+ },
266
+ });
267
+ expect((await store?.read())?.state).toBe('unavailable');
268
+ });
269
+
270
+ test('an unrecognised payload from an older sibling is unavailable, never absent', async () => {
271
+ const store = loadStore('android', {
272
+ broker: { read: async () => ({ ok: true }), write: async () => true, clear: async () => undefined },
273
+ });
274
+ expect((await store?.read())?.state).toBe('unavailable');
275
+ });
276
+
277
+ test('the slot is unsupported when the native module is not linked', async () => {
278
+ const store = loadStore('android', { broker: null });
279
+ expect((await store?.read())?.state).toBe('unsupported');
280
+ await expect(store?.publish(CRED)).resolves.toBe(false);
281
+ });
282
+
283
+ test('publish forwards the broker’s own read-back verdict', async () => {
284
+ const unverified = loadStore('android', {
285
+ broker: { read: async () => ({ status: 'absent' }), write: async () => false, clear: async () => undefined },
286
+ });
287
+ await expect(unverified?.publish(CRED)).resolves.toBe(false);
288
+ });
289
+ });
@@ -1,25 +1,66 @@
1
1
  /**
2
2
  * Platform `AuthStateStore` for `@oxyhq/services`.
3
3
  *
4
- * The zero-cookie device model persists the durable device credential
5
- * (`deviceId` + `deviceSecret`) per origin (web) / per device (native), and the
6
- * SDK re-mints the access token from that credential on cold boot. `@oxyhq/core`
7
- * owns the store shape + logic (`createWebAuthStateStore` /
8
- * `createNativeAuthStateStore`); this module only selects the platform storage
9
- * seam:
4
+ * The device model persists the durable device credential (`deviceId` +
5
+ * `deviceSecret`) per origin (web) / per device (native), and the SDK re-mints
6
+ * the access token from that credential on cold boot. `@oxyhq/core` owns the
7
+ * store shape + logic (`createWebAuthStateStore` / `createNativeAuthStateStore` /
8
+ * `createMemoryAuthStateStore`); this module only selects the seam:
10
9
  *
10
+ * - `storage: 'ephemeral'` → `createMemoryAuthStateStore()`, on EVERY platform.
11
11
  * - web → `createWebAuthStateStore()` (localStorage, in-memory fallback).
12
12
  * - native → `createNativeAuthStateStore(secureKV)` for the SESSION blob over
13
13
  * the shared `createNativeSecureKeyValueStorage()` adapter
14
- * (`expo-secure-store`, AsyncStorage fallback).
14
+ * (`expo-secure-store`, AsyncStorage fallback), WRAPPED so every credential
15
+ * it persists is also mirrored into the device-wide shared slot.
16
+ *
17
+ * The native wrapper is how several official apps end up on ONE `DeviceSession`
18
+ * (and therefore one active context): whichever app proves a credential publishes
19
+ * it, and a later-installed sibling adopts it during cold boot instead of asking
20
+ * for the Commons identity key. The mirror is additive — it can neither change
21
+ * nor fail the app's own durable write.
15
22
  */
16
23
  import {
17
24
  createWebAuthStateStore,
18
25
  createNativeAuthStateStore,
26
+ createMemoryAuthStateStore,
27
+ createSharedMirroringAuthStateStore,
19
28
  type AuthStateStore,
29
+ type SessionMode,
20
30
  } from '@oxyhq/core';
21
31
  import { isReactNative } from '../utils/storageHelpers';
22
32
  import { createNativeSecureKeyValueStorage } from './nativeSecureStorage';
33
+ import { createPlatformSharedDeviceCredentialStore } from './sharedDeviceCredentialStore';
34
+
35
+ export interface PlatformAuthStateStoreOptions {
36
+ /**
37
+ * Who owns the session this provider resolves. Only `'account'` mirrors into
38
+ * the device-wide shared slot.
39
+ *
40
+ * `'identity'` (the vault) is deliberately excluded, which keeps its storage
41
+ * behaviour byte-for-byte what it is today. The vault's credential is a
42
+ * perfectly valid device credential, so publishing it would arguably be
43
+ * correct — but it would also let every ordinary app on the device join the
44
+ * vault's device session as a side effect of the vault persisting a token, and
45
+ * "a background write changes which session five other apps boot into" is not
46
+ * a decision a storage seam gets to make.
47
+ */
48
+ sessionMode?: SessionMode;
49
+ /**
50
+ * Whether this origin/app may persist a durable device credential AT ALL.
51
+ *
52
+ * `'ephemeral'` stores nothing durable and mirrors nothing: the session lives
53
+ * in memory for the lifetime of the page and is gone on reload. Its one caller
54
+ * is `auth.oxy.so` with the browser hub enabled (issue #937 Phase 5, ADR 0003),
55
+ * where the durable credential for the browser profile is the server-side
56
+ * DeviceSession behind the `__Host-oxy-device` handle.
57
+ *
58
+ * See `OxyProviderProps.deviceCredentialStorage` for why the answer to "let the
59
+ * hub be authoritative" is to stop persisting the other credential rather than
60
+ * to consult it second.
61
+ */
62
+ storage?: 'persistent' | 'ephemeral';
63
+ }
23
64
 
24
65
  /**
25
66
  * Build the platform {@link AuthStateStore} for this runtime.
@@ -27,11 +68,39 @@ import { createNativeSecureKeyValueStorage } from './nativeSecureStorage';
27
68
  * Native persists the SESSION blob (`deviceId` + `deviceSecret` + cached access
28
69
  * token) per-app in SecureStore; the SDK re-mints the access token from the
29
70
  * device credential on the next cold boot.
71
+ *
72
+ * ## The ephemeral check is FIRST, and the order is load-bearing
73
+ *
74
+ * It short-circuits above the `isReactNative()` branch so an ephemeral caller can
75
+ * never reach the native path — and therefore can never reach the shared-slot
76
+ * mirroring wrapper. Checked after that branch instead, an origin that has
77
+ * declined to persist a credential would publish one into the device-wide slot
78
+ * every sibling app adopts on cold boot: it would keep nothing itself while
79
+ * deciding which session five other apps boot into.
80
+ *
81
+ * That is unreachable today because the only ephemeral caller is a web origin, so
82
+ * `isReactNative()` is false there anyway. Unreachable today is exactly the kind
83
+ * of guarantee that stops holding when someone adds the second caller, so it is
84
+ * structural here rather than incidental, and
85
+ * `__tests__/session/authStoreEphemeral.test.ts` holds the ordering directly.
30
86
  */
31
- export function createPlatformAuthStateStore(): AuthStateStore {
87
+ export function createPlatformAuthStateStore(
88
+ options: PlatformAuthStateStoreOptions = {},
89
+ ): AuthStateStore {
90
+ // FIRST, above every platform branch — see the docblock for why the ordering
91
+ // is the guarantee and not a coincidence.
92
+ if (options.storage === 'ephemeral') {
93
+ return createMemoryAuthStateStore();
94
+ }
95
+
32
96
  if (!isReactNative()) {
33
97
  return createWebAuthStateStore();
34
98
  }
35
99
 
36
- return createNativeAuthStateStore(createNativeSecureKeyValueStorage());
100
+ const local = createNativeAuthStateStore(createNativeSecureKeyValueStorage());
101
+ if (options.sessionMode === 'identity') {
102
+ return local;
103
+ }
104
+ const shared = createPlatformSharedDeviceCredentialStore();
105
+ return shared ? createSharedMirroringAuthStateStore({ local, shared }) : local;
37
106
  }