@oxyhq/services 28.0.0 → 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 (324) hide show
  1. package/NOTICE +10 -9
  2. package/README.md +65 -2
  3. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionModule.kt +178 -0
  4. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionProvider.kt +99 -0
  5. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionStore.kt +115 -0
  6. package/expo-module.config.json +1 -0
  7. package/lib/commonjs/index.js +60 -16
  8. package/lib/commonjs/index.js.map +1 -1
  9. package/lib/commonjs/ui/boot/runProviderColdBoot.js +7 -0
  10. package/lib/commonjs/ui/boot/runProviderColdBoot.js.map +1 -1
  11. package/lib/commonjs/ui/client.js +12 -7
  12. package/lib/commonjs/ui/client.js.map +1 -1
  13. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +10 -27
  14. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
  15. package/lib/commonjs/ui/components/OxyAuthChooser.js +132 -44
  16. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  17. package/lib/commonjs/ui/components/OxyProvider.js +4 -2
  18. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  19. package/lib/commonjs/ui/components/SurfaceScreen.js +31 -3
  20. package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
  21. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +209 -84
  22. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  23. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js +25 -7
  24. package/lib/commonjs/ui/components/authChooser/SignInEntryView.js.map +1 -1
  25. package/lib/commonjs/ui/components/authChooser/primitives.js +35 -22
  26. package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
  27. package/lib/commonjs/ui/components/authChooser/types.js +11 -0
  28. package/lib/commonjs/ui/components/authChooser/types.js.map +1 -1
  29. package/lib/commonjs/ui/context/OxyContext.js +257 -306
  30. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  31. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +27 -37
  32. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  33. package/lib/commonjs/ui/context/oxyContextHelpers.js +0 -29
  34. package/lib/commonjs/ui/context/oxyContextHelpers.js.map +1 -1
  35. package/lib/commonjs/ui/context/useOxyAccountGraph.js +6 -17
  36. package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
  37. package/lib/commonjs/ui/hooks/accountDialogSnapshot.js +42 -0
  38. package/lib/commonjs/ui/hooks/accountDialogSnapshot.js.map +1 -0
  39. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +0 -19
  40. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  41. package/lib/commonjs/ui/hooks/useDeviceSwitcher.js +57 -0
  42. package/lib/commonjs/ui/hooks/useDeviceSwitcher.js.map +1 -0
  43. package/lib/commonjs/ui/hooks/useI18n.js +22 -3
  44. package/lib/commonjs/ui/hooks/useI18n.js.map +1 -1
  45. package/lib/commonjs/ui/hooks/useSessionManagement.js +46 -153
  46. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  47. package/lib/commonjs/ui/index.js +12 -7
  48. package/lib/commonjs/ui/index.js.map +1 -1
  49. package/lib/commonjs/ui/navigation/routes.js +85 -73
  50. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  51. package/lib/commonjs/ui/navigation/surfaces.js +8 -7
  52. package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
  53. package/lib/commonjs/ui/runtime/createOxyRuntime.js +433 -0
  54. package/lib/commonjs/ui/runtime/createOxyRuntime.js.map +1 -0
  55. package/lib/commonjs/ui/runtime/index.js +63 -0
  56. package/lib/commonjs/ui/runtime/index.js.map +1 -0
  57. package/lib/commonjs/ui/runtime/runtimeContext.js +83 -0
  58. package/lib/commonjs/ui/runtime/runtimeContext.js.map +1 -0
  59. package/lib/commonjs/ui/runtime/types.js +6 -0
  60. package/lib/commonjs/ui/runtime/types.js.map +1 -0
  61. package/lib/commonjs/ui/runtime/useRuntimeSnapshot.js +57 -0
  62. package/lib/commonjs/ui/runtime/useRuntimeSnapshot.js.map +1 -0
  63. package/lib/commonjs/ui/server.js +1 -2
  64. package/lib/commonjs/ui/server.js.map +1 -1
  65. package/lib/commonjs/ui/session/authStore.js +45 -9
  66. package/lib/commonjs/ui/session/authStore.js.map +1 -1
  67. package/lib/commonjs/ui/session/sharedDeviceCredentialStore.js +306 -0
  68. package/lib/commonjs/ui/session/sharedDeviceCredentialStore.js.map +1 -0
  69. package/lib/commonjs/ui/stores/authStore.js +154 -55
  70. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  71. package/lib/commonjs/ui/utils/avatarUtils.js +2 -36
  72. package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
  73. package/lib/module/index.js +16 -8
  74. package/lib/module/index.js.map +1 -1
  75. package/lib/module/ui/boot/runProviderColdBoot.js +7 -0
  76. package/lib/module/ui/boot/runProviderColdBoot.js.map +1 -1
  77. package/lib/module/ui/client.js +1 -2
  78. package/lib/module/ui/client.js.map +1 -1
  79. package/lib/module/ui/components/OxyAccountDialogScreen.js +10 -27
  80. package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
  81. package/lib/module/ui/components/OxyAuthChooser.js +134 -44
  82. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  83. package/lib/module/ui/components/OxyProvider.js +5 -3
  84. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  85. package/lib/module/ui/components/SurfaceScreen.js +33 -5
  86. package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
  87. package/lib/module/ui/components/authChooser/AccountsMenuView.js +210 -85
  88. package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  89. package/lib/module/ui/components/authChooser/SignInEntryView.js +25 -7
  90. package/lib/module/ui/components/authChooser/SignInEntryView.js.map +1 -1
  91. package/lib/module/ui/components/authChooser/primitives.js +35 -22
  92. package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
  93. package/lib/module/ui/components/authChooser/types.js +11 -0
  94. package/lib/module/ui/components/authChooser/types.js.map +1 -1
  95. package/lib/module/ui/context/OxyContext.js +251 -303
  96. package/lib/module/ui/context/OxyContext.js.map +1 -1
  97. package/lib/module/ui/context/hooks/useAuthOperations.js +27 -37
  98. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  99. package/lib/module/ui/context/oxyContextHelpers.js +0 -28
  100. package/lib/module/ui/context/oxyContextHelpers.js.map +1 -1
  101. package/lib/module/ui/context/useOxyAccountGraph.js +6 -17
  102. package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
  103. package/lib/module/ui/hooks/accountDialogSnapshot.js +38 -0
  104. package/lib/module/ui/hooks/accountDialogSnapshot.js.map +1 -0
  105. package/lib/module/ui/hooks/mutations/useAccountMutations.js +0 -19
  106. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  107. package/lib/module/ui/hooks/useDeviceSwitcher.js +53 -0
  108. package/lib/module/ui/hooks/useDeviceSwitcher.js.map +1 -0
  109. package/lib/module/ui/hooks/useI18n.js +24 -4
  110. package/lib/module/ui/hooks/useI18n.js.map +1 -1
  111. package/lib/module/ui/hooks/useSessionManagement.js +47 -155
  112. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  113. package/lib/module/ui/index.js +1 -2
  114. package/lib/module/ui/index.js.map +1 -1
  115. package/lib/module/ui/navigation/routes.js +84 -72
  116. package/lib/module/ui/navigation/routes.js.map +1 -1
  117. package/lib/module/ui/navigation/surfaces.js +6 -6
  118. package/lib/module/ui/navigation/surfaces.js.map +1 -1
  119. package/lib/module/ui/runtime/createOxyRuntime.js +430 -0
  120. package/lib/module/ui/runtime/createOxyRuntime.js.map +1 -0
  121. package/lib/module/ui/runtime/index.js +15 -0
  122. package/lib/module/ui/runtime/index.js.map +1 -0
  123. package/lib/module/ui/runtime/runtimeContext.js +75 -0
  124. package/lib/module/ui/runtime/runtimeContext.js.map +1 -0
  125. package/lib/module/ui/runtime/types.js +4 -0
  126. package/lib/module/ui/runtime/types.js.map +1 -0
  127. package/lib/module/ui/runtime/useRuntimeSnapshot.js +52 -0
  128. package/lib/module/ui/runtime/useRuntimeSnapshot.js.map +1 -0
  129. package/lib/module/ui/server.js +0 -1
  130. package/lib/module/ui/server.js.map +1 -1
  131. package/lib/module/ui/session/authStore.js +46 -11
  132. package/lib/module/ui/session/authStore.js.map +1 -1
  133. package/lib/module/ui/session/sharedDeviceCredentialStore.js +302 -0
  134. package/lib/module/ui/session/sharedDeviceCredentialStore.js.map +1 -0
  135. package/lib/module/ui/stores/authStore.js +154 -55
  136. package/lib/module/ui/stores/authStore.js.map +1 -1
  137. package/lib/module/ui/utils/avatarUtils.js +2 -35
  138. package/lib/module/ui/utils/avatarUtils.js.map +1 -1
  139. package/lib/typescript/commonjs/index.d.ts +5 -3
  140. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  141. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  142. package/lib/typescript/commonjs/ui/client.d.ts +1 -2
  143. package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
  144. package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  145. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  146. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  147. package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
  148. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts +11 -4
  149. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  150. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts +3 -1
  151. package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts.map +1 -1
  152. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +18 -6
  153. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -1
  154. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +33 -1
  155. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts.map +1 -1
  156. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +35 -4
  157. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  158. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +8 -12
  159. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  160. package/lib/typescript/commonjs/ui/context/oxyContextHelpers.d.ts +0 -2
  161. package/lib/typescript/commonjs/ui/context/oxyContextHelpers.d.ts.map +1 -1
  162. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +9 -1
  163. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
  164. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts +1 -3
  165. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  166. package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts +15 -0
  167. package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts.map +1 -0
  168. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts +49 -0
  170. package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts.map +1 -0
  171. package/lib/typescript/commonjs/ui/hooks/useI18n.d.ts +13 -0
  172. package/lib/typescript/commonjs/ui/hooks/useI18n.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts +23 -18
  174. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/ui/index.d.ts +1 -2
  176. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  177. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +15 -1
  178. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  179. package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
  180. package/lib/typescript/commonjs/ui/runtime/createOxyRuntime.d.ts +144 -0
  181. package/lib/typescript/commonjs/ui/runtime/createOxyRuntime.d.ts.map +1 -0
  182. package/lib/typescript/commonjs/ui/runtime/index.d.ts +16 -0
  183. package/lib/typescript/commonjs/ui/runtime/index.d.ts.map +1 -0
  184. package/lib/typescript/commonjs/ui/runtime/runtimeContext.d.ts +43 -0
  185. package/lib/typescript/commonjs/ui/runtime/runtimeContext.d.ts.map +1 -0
  186. package/lib/typescript/commonjs/ui/runtime/types.d.ts +89 -0
  187. package/lib/typescript/commonjs/ui/runtime/types.d.ts.map +1 -0
  188. package/lib/typescript/commonjs/ui/runtime/useRuntimeSnapshot.d.ts +23 -0
  189. package/lib/typescript/commonjs/ui/runtime/useRuntimeSnapshot.d.ts.map +1 -0
  190. package/lib/typescript/commonjs/ui/server.d.ts +0 -1
  191. package/lib/typescript/commonjs/ui/server.d.ts.map +1 -1
  192. package/lib/typescript/commonjs/ui/session/authStore.d.ts +60 -9
  193. package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/ui/session/sharedDeviceCredentialStore.d.ts +32 -0
  195. package/lib/typescript/commonjs/ui/session/sharedDeviceCredentialStore.d.ts.map +1 -0
  196. package/lib/typescript/commonjs/ui/stores/authStore.d.ts +49 -5
  197. package/lib/typescript/commonjs/ui/stores/authStore.d.ts.map +1 -1
  198. package/lib/typescript/commonjs/ui/types/navigation.d.ts +26 -0
  199. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  200. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts +2 -10
  201. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
  202. package/lib/typescript/module/index.d.ts +5 -3
  203. package/lib/typescript/module/index.d.ts.map +1 -1
  204. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  205. package/lib/typescript/module/ui/client.d.ts +1 -2
  206. package/lib/typescript/module/ui/client.d.ts.map +1 -1
  207. package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  208. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  209. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  210. package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
  211. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts +11 -4
  212. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  213. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts +3 -1
  214. package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts.map +1 -1
  215. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +18 -6
  216. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -1
  217. package/lib/typescript/module/ui/components/authChooser/types.d.ts +33 -1
  218. package/lib/typescript/module/ui/components/authChooser/types.d.ts.map +1 -1
  219. package/lib/typescript/module/ui/context/OxyContext.d.ts +35 -4
  220. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  221. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +8 -12
  222. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  223. package/lib/typescript/module/ui/context/oxyContextHelpers.d.ts +0 -2
  224. package/lib/typescript/module/ui/context/oxyContextHelpers.d.ts.map +1 -1
  225. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +9 -1
  226. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
  227. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts +1 -3
  228. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  229. package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts +15 -0
  230. package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts.map +1 -0
  231. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  232. package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts +49 -0
  233. package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts.map +1 -0
  234. package/lib/typescript/module/ui/hooks/useI18n.d.ts +13 -0
  235. package/lib/typescript/module/ui/hooks/useI18n.d.ts.map +1 -1
  236. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts +23 -18
  237. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
  238. package/lib/typescript/module/ui/index.d.ts +1 -2
  239. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  240. package/lib/typescript/module/ui/navigation/routes.d.ts +15 -1
  241. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  242. package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
  243. package/lib/typescript/module/ui/runtime/createOxyRuntime.d.ts +144 -0
  244. package/lib/typescript/module/ui/runtime/createOxyRuntime.d.ts.map +1 -0
  245. package/lib/typescript/module/ui/runtime/index.d.ts +16 -0
  246. package/lib/typescript/module/ui/runtime/index.d.ts.map +1 -0
  247. package/lib/typescript/module/ui/runtime/runtimeContext.d.ts +43 -0
  248. package/lib/typescript/module/ui/runtime/runtimeContext.d.ts.map +1 -0
  249. package/lib/typescript/module/ui/runtime/types.d.ts +89 -0
  250. package/lib/typescript/module/ui/runtime/types.d.ts.map +1 -0
  251. package/lib/typescript/module/ui/runtime/useRuntimeSnapshot.d.ts +23 -0
  252. package/lib/typescript/module/ui/runtime/useRuntimeSnapshot.d.ts.map +1 -0
  253. package/lib/typescript/module/ui/server.d.ts +0 -1
  254. package/lib/typescript/module/ui/server.d.ts.map +1 -1
  255. package/lib/typescript/module/ui/session/authStore.d.ts +60 -9
  256. package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
  257. package/lib/typescript/module/ui/session/sharedDeviceCredentialStore.d.ts +32 -0
  258. package/lib/typescript/module/ui/session/sharedDeviceCredentialStore.d.ts.map +1 -0
  259. package/lib/typescript/module/ui/stores/authStore.d.ts +49 -5
  260. package/lib/typescript/module/ui/stores/authStore.d.ts.map +1 -1
  261. package/lib/typescript/module/ui/types/navigation.d.ts +26 -0
  262. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  263. package/lib/typescript/module/ui/utils/avatarUtils.d.ts +2 -10
  264. package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
  265. package/package.json +6 -7
  266. package/plugins/withSharedDeviceSessionProvider.js +102 -0
  267. package/plugins/withSharedDeviceSessionReader.js +57 -0
  268. package/src/__tests__/esmSourcePurity.test.ts +61 -0
  269. package/src/index.ts +31 -9
  270. package/src/ui/boot/runProviderColdBoot.ts +7 -0
  271. package/src/ui/client.ts +1 -2
  272. package/src/ui/components/OxyAccountDialogScreen.tsx +10 -29
  273. package/src/ui/components/OxyAuthChooser.tsx +149 -50
  274. package/src/ui/components/OxyProvider.tsx +7 -5
  275. package/src/ui/components/SurfaceScreen.tsx +28 -4
  276. package/src/ui/components/authChooser/AccountsMenuView.tsx +246 -96
  277. package/src/ui/components/authChooser/SignInEntryView.tsx +31 -8
  278. package/src/ui/components/authChooser/primitives.tsx +37 -23
  279. package/src/ui/components/authChooser/types.ts +34 -1
  280. package/src/ui/context/OxyContext.tsx +269 -324
  281. package/src/ui/context/hooks/useAuthOperations.ts +32 -35
  282. package/src/ui/context/oxyContextHelpers.ts +0 -30
  283. package/src/ui/context/oxyContextTypes.ts +9 -1
  284. package/src/ui/context/useOxyAccountGraph.ts +5 -19
  285. package/src/ui/hooks/accountDialogSnapshot.ts +37 -0
  286. package/src/ui/hooks/mutations/useAccountMutations.ts +0 -19
  287. package/src/ui/hooks/queries/__tests__/userCache.test.ts +12 -1
  288. package/src/ui/hooks/useDeviceSwitcher.ts +110 -0
  289. package/src/ui/hooks/useI18n.ts +23 -3
  290. package/src/ui/hooks/useSessionManagement.ts +62 -211
  291. package/src/ui/index.ts +1 -2
  292. package/src/ui/navigation/routes.ts +85 -75
  293. package/src/ui/navigation/surfaces.ts +6 -9
  294. package/src/ui/runtime/createOxyRuntime.ts +623 -0
  295. package/src/ui/runtime/index.ts +34 -0
  296. package/src/ui/runtime/runtimeContext.tsx +111 -0
  297. package/src/ui/runtime/types.ts +110 -0
  298. package/src/ui/runtime/useRuntimeSnapshot.ts +52 -0
  299. package/src/ui/server.ts +0 -1
  300. package/src/ui/session/__tests__/authStore.test.ts +90 -0
  301. package/src/ui/session/__tests__/sharedDeviceCredentialStore.test.ts +289 -0
  302. package/src/ui/session/authStore.ts +78 -9
  303. package/src/ui/session/sharedDeviceCredentialStore.ts +318 -0
  304. package/src/ui/stores/authStore.ts +171 -43
  305. package/src/ui/types/navigation.ts +26 -0
  306. package/src/ui/utils/avatarUtils.ts +2 -37
  307. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +0 -64
  308. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +0 -1
  309. package/lib/commonjs/ui/stores/accountStore.js +0 -221
  310. package/lib/commonjs/ui/stores/accountStore.js.map +0 -1
  311. package/lib/module/ui/hooks/useSwitchableAccounts.js +0 -60
  312. package/lib/module/ui/hooks/useSwitchableAccounts.js.map +0 -1
  313. package/lib/module/ui/stores/accountStore.js +0 -213
  314. package/lib/module/ui/stores/accountStore.js.map +0 -1
  315. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +0 -23
  316. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +0 -1
  317. package/lib/typescript/commonjs/ui/stores/accountStore.d.ts +0 -27
  318. package/lib/typescript/commonjs/ui/stores/accountStore.d.ts.map +0 -1
  319. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +0 -23
  320. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +0 -1
  321. package/lib/typescript/module/ui/stores/accountStore.d.ts +0 -27
  322. package/lib/typescript/module/ui/stores/accountStore.d.ts.map +0 -1
  323. package/src/ui/hooks/useSwitchableAccounts.ts +0 -75
  324. package/src/ui/stores/accountStore.ts +0 -264
@@ -1,7 +1,6 @@
1
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
1
+ import { useCallback, useMemo, useRef } from 'react';
2
2
  import { isDev, type ApiError, type User } from '@oxyhq/core';
3
3
  import type { ClientSession } from '@oxyhq/core';
4
- import { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual } from '@oxyhq/core';
5
4
  import { fetchSessionsWithFallback } from '../utils/sessionHelpers';
6
5
  import { getStorageKeys, type StorageInterface } from '../utils/storageHelpers';
7
6
  import { handleAuthError, isInvalidSessionError } from '../utils/errorHandlers';
@@ -10,109 +9,80 @@ import type { QueryClient } from '@tanstack/react-query';
10
9
  import { clearQueryCache } from './queryClient';
11
10
  import { isWebBrowser } from '../utils/isWebBrowser';
12
11
  import { resetSessionScopedStores } from '../stores/resetSessionScopedStores';
12
+ import type { OxyRuntime } from '../runtime';
13
13
 
14
14
  export interface UseSessionManagementOptions {
15
15
  oxyServices: OxyServices;
16
+ /** The one owner of `sessions` / `activeSessionId` / the signed-in account. */
17
+ runtime: OxyRuntime;
16
18
  storage: StorageInterface | null;
17
19
  storageKeyPrefix?: string;
18
- loginSuccess: (user: User) => void;
19
- logoutStore: () => void;
20
20
  onAuthStateChange?: (user: User | null) => void;
21
21
  onError?: (error: ApiError) => void;
22
22
  setAuthError?: (message: string | null) => void;
23
23
  logger?: (message: string, error?: unknown) => void;
24
- setTokenReady?: (ready: boolean) => void;
25
24
  queryClient?: QueryClient | null;
26
25
  }
27
26
 
28
27
  export interface UseSessionManagementResult {
29
- sessions: ClientSession[];
30
- activeSessionId: string | null;
31
- setActiveSessionId: (sessionId: string | null) => void;
32
- updateSessions: (incoming: ClientSession[], options?: { merge?: boolean; preserveSessionIds?: string[] }) => void;
28
+ /** Persist the projected session-id list. Handed to the runtime as its projection sink. */
29
+ saveSessionIds: (sessionIds: string[]) => void;
30
+ saveActiveSessionId: (sessionId: string) => Promise<void>;
31
+ /**
32
+ * The legacy `validateSession`-keyed switch. Reachable from exactly ONE
33
+ * caller: `performSignIn`'s same-user duplicate-session dedup. The switch a
34
+ * consumer sees on the context is the `SessionClient` one in `OxyContext`.
35
+ */
33
36
  switchSession: (sessionId: string) => Promise<User>;
34
- refreshSessions: (activeUserId?: string) => Promise<void>;
37
+ /** Tear down the local session: runtime projection, caches, storage, tokens. */
35
38
  clearSessionState: () => Promise<void>;
36
- saveActiveSessionId: (sessionId: string) => Promise<void>;
37
- trackRemovedSession: (sessionId: string) => void;
38
39
  storageKeys: ReturnType<typeof getStorageKeys>;
39
- isRefreshInFlight: boolean;
40
40
  }
41
41
 
42
42
  const DEFAULT_SAVE_ERROR_MESSAGE = 'Failed to save session data';
43
43
  const CLEAR_STORAGE_ERROR = 'Failed to clear storage';
44
44
 
45
45
  /**
46
- * Manage session state, persistence, and high-level multi-session operations.
46
+ * Session persistence and the one legacy switch left, over the runtime.
47
47
  *
48
- * @param options - Session management configuration
48
+ * This hook used to hold its OWN `sessions` / `activeSessionId` React state
49
+ * plus six refs mirroring them so its callbacks could avoid widening their
50
+ * dependency arrays. That made it a second owner of facts `SessionClient`
51
+ * already had, reconciled only by whichever `useEffect` ran last. Both are gone:
52
+ * the runtime owns them, this hook writes through it, and the refs mirrored
53
+ * nothing once there was nothing local to mirror.
54
+ *
55
+ * `refreshSessions`, `trackRemovedSession` and `isRefreshInFlight` are deleted
56
+ * outright — every one of them was dropped unread at the single call site.
49
57
  */
50
58
  export const useSessionManagement = ({
51
59
  oxyServices,
60
+ runtime,
52
61
  storage,
53
62
  storageKeyPrefix,
54
- loginSuccess,
55
- logoutStore,
56
63
  onAuthStateChange,
57
64
  onError,
58
65
  setAuthError,
59
66
  logger,
60
- setTokenReady,
61
67
  queryClient,
62
68
  }: UseSessionManagementOptions): UseSessionManagementResult => {
63
- const [sessions, setSessions] = useState<ClientSession[]>([]);
64
- const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
65
-
66
- // Refs to avoid recreating callbacks when sessions/activeSessionId change
67
- const sessionsRef = useRef(sessions);
68
- sessionsRef.current = sessions;
69
- const activeSessionIdRef = useRef(activeSessionId);
70
- activeSessionIdRef.current = activeSessionId;
71
-
72
- const refreshInFlightRef = useRef<Promise<void> | null>(null);
73
- const removedSessionsRef = useRef<Set<string>>(new Set());
74
- const lastRefreshRef = useRef<number>(0);
75
-
76
69
  const storageKeys = useMemo(() => getStorageKeys(storageKeyPrefix), [storageKeyPrefix]);
70
+ const runtimeRef = useRef(runtime);
71
+ runtimeRef.current = runtime;
77
72
 
78
73
  const saveSessionIds = useCallback(
79
- async (sessionIds: string[]): Promise<void> => {
74
+ (sessionIds: string[]): void => {
80
75
  if (!storage) return;
81
- try {
82
- const uniqueIds = Array.from(new Set(sessionIds));
83
- await storage.setItem(storageKeys.sessionIds, JSON.stringify(uniqueIds));
84
- } catch (error) {
76
+ const uniqueIds = Array.from(new Set(sessionIds));
77
+ storage.setItem(storageKeys.sessionIds, JSON.stringify(uniqueIds)).catch((error: unknown) => {
85
78
  if (logger) {
86
79
  logger(DEFAULT_SAVE_ERROR_MESSAGE, error);
87
80
  } else if (isDev()) {
88
81
  console.warn('Failed to save session IDs:', error);
89
82
  }
90
- }
91
- },
92
- [logger, storage, storageKeys.sessionIds],
93
- );
94
-
95
- const updateSessions = useCallback(
96
- (incoming: ClientSession[], options: { merge?: boolean; preserveSessionIds?: string[] } = {}): void => {
97
- setSessions((prevSessions) => {
98
- const processed = options.merge
99
- ? mergeSessions(prevSessions, incoming, activeSessionIdRef.current, false)
100
- : normalizeAndSortSessions(incoming, activeSessionIdRef.current, false);
101
-
102
- if (storage) {
103
- void saveSessionIds([
104
- ...processed.map((session) => session.sessionId),
105
- ...(options.preserveSessionIds ?? []),
106
- ]);
107
- }
108
-
109
- if (sessionsArraysEqual(prevSessions, processed)) {
110
- return prevSessions;
111
- }
112
- return processed;
113
83
  });
114
84
  },
115
- [saveSessionIds, storage],
85
+ [logger, storage, storageKeys.sessionIds],
116
86
  );
117
87
 
118
88
  const saveActiveSessionId = useCallback(
@@ -133,27 +103,11 @@ export const useSessionManagement = ({
133
103
  [logger, onError, setAuthError, storage, storageKeys.activeSessionId],
134
104
  );
135
105
 
136
- const removeActiveSessionId = useCallback(async (): Promise<void> => {
137
- if (!storage) return;
138
- try {
139
- await storage.removeItem(storageKeys.activeSessionId);
140
- } catch (error) {
141
- handleAuthError(error, {
142
- defaultMessage: DEFAULT_SAVE_ERROR_MESSAGE,
143
- code: 'SESSION_PERSISTENCE_ERROR',
144
- onError,
145
- setAuthError,
146
- logger,
147
- });
148
- }
149
- }, [logger, onError, setAuthError, storage, storageKeys.activeSessionId]);
150
-
151
106
  const clearSessionStorage = useCallback(async (): Promise<void> => {
152
107
  if (!storage) return;
153
108
  try {
154
109
  await storage.removeItem(storageKeys.activeSessionId);
155
110
  await storage.removeItem(storageKeys.sessionIds);
156
- // Note: Identity sync state ('oxy_identity_synced') is managed by accounts app
157
111
  } catch (error) {
158
112
  handleAuthError(error, {
159
113
  defaultMessage: CLEAR_STORAGE_ERROR,
@@ -166,25 +120,21 @@ export const useSessionManagement = ({
166
120
  }, [logger, onError, setAuthError, storage, storageKeys.activeSessionId, storageKeys.sessionIds]);
167
121
 
168
122
  const clearSessionState = useCallback(async (): Promise<void> => {
169
- setSessions([]);
170
- setActiveSessionId(null);
171
- logoutStore();
123
+ runtimeRef.current.clearSession();
172
124
  resetSessionScopedStores();
173
125
 
174
- // Clear the access token on the client instance. Without this the
175
- // TokenStore retained the stale bearer until the next 401, leaving the
176
- // instance "logged in" at the HTTP layer and — via OxyProvider's
177
- // token-change mirror — leaking that stale token onto the shared
178
- // `oxyClient` singleton after sign-out. Clearing here fires
179
- // `onTokensChanged(null)`, propagating the logged-out state everywhere.
126
+ // Clear the access token on the client instance. Without this the token
127
+ // store retained the stale bearer until the next 401, leaving the instance
128
+ // "logged in" at the HTTP layer and — via the provider's token mirror —
129
+ // leaking that stale token onto the shared `oxyClient` singleton after
130
+ // sign-out. Clearing here fires `onTokensChanged(null)`, propagating the
131
+ // logged-out state everywhere.
180
132
  oxyServices.clearTokens();
181
133
 
182
- // Clear TanStack Query cache (in-memory)
183
134
  if (queryClient) {
184
135
  queryClient.clear();
185
136
  }
186
-
187
- // Clear persisted query cache
137
+
188
138
  if (storage) {
189
139
  try {
190
140
  await clearQueryCache(storage);
@@ -194,49 +144,19 @@ export const useSessionManagement = ({
194
144
  }
195
145
  }
196
146
  }
197
-
147
+
198
148
  await clearSessionStorage();
199
149
  onAuthStateChange?.(null);
200
- }, [clearSessionStorage, logoutStore, onAuthStateChange, oxyServices, queryClient, storage, logger]);
201
-
202
- const activateSession = useCallback(
203
- async (sessionId: string, user: User): Promise<void> => {
204
- setTokenReady?.(true);
205
- setActiveSessionId(sessionId);
206
- loginSuccess(user);
207
- await saveActiveSessionId(sessionId);
208
- onAuthStateChange?.(user);
209
- },
210
- [loginSuccess, onAuthStateChange, saveActiveSessionId, setTokenReady],
211
- );
212
-
213
- const removalTimerIdsRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());
214
-
215
- const trackRemovedSession = useCallback((sessionId: string) => {
216
- removedSessionsRef.current.add(sessionId);
217
- const timerId = setTimeout(() => {
218
- removedSessionsRef.current.delete(sessionId);
219
- removalTimerIdsRef.current.delete(timerId);
220
- }, 5000);
221
- removalTimerIdsRef.current.add(timerId);
222
- }, []);
223
-
224
- useEffect(() => {
225
- return () => {
226
- removalTimerIdsRef.current.forEach(clearTimeout);
227
- };
228
- }, []);
150
+ }, [clearSessionStorage, onAuthStateChange, oxyServices, queryClient, storage, logger]);
229
151
 
230
152
  const switchSession = useCallback(
231
153
  async (sessionId: string): Promise<User> => {
232
154
  try {
233
- // On web, the bearer must already be in memory (planted by
234
- // `claimSessionByToken`, a cold-boot silent-restore step, or a prior
155
+ // On web the bearer must already be in memory (planted by
156
+ // `claimSessionByToken`, a cold-boot restore step, or a prior
235
157
  // `SessionClient` sync) before validating — there is no client-side
236
- // `oxy_rt` refresh-cookie slot to fall back on; the device account SET
237
- // is server-authoritative via `SessionClient` now. The native path
238
- // arrives here only after a bearer has been planted by
239
- // `claimSessionByToken` or secure shared-session restore.
158
+ // refresh-cookie slot to fall back on. The native path arrives here only
159
+ // after a bearer has been planted too.
240
160
  if (isWebBrowser() && !oxyServices.getAccessToken()) {
241
161
  throw new Error('Session is invalid or expired');
242
162
  }
@@ -245,20 +165,26 @@ export const useSessionManagement = ({
245
165
  if (!validation?.valid) {
246
166
  throw new Error('Session is invalid or expired');
247
167
  }
248
-
249
168
  if (!validation.user) {
250
169
  throw new Error('User data not available from session validation');
251
170
  }
252
171
 
253
172
  const user = validation.user as User;
254
- await activateSession(sessionId, user);
173
+ const activeRuntime = runtimeRef.current;
174
+ activeRuntime.batch(() => {
175
+ activeRuntime.setTokenReady(true);
176
+ activeRuntime.setActiveSessionId(sessionId);
177
+ activeRuntime.setAccount(user);
178
+ });
179
+ await saveActiveSessionId(sessionId);
180
+ onAuthStateChange?.(user);
255
181
 
256
182
  try {
257
183
  const deviceSessions = await fetchSessionsWithFallback(oxyServices, sessionId, {
258
184
  fallbackUserId: user.id,
259
185
  logger,
260
186
  });
261
- updateSessions(deviceSessions, { merge: true });
187
+ activeRuntime.mergeSessions(deviceSessions, { merge: true });
262
188
  } catch (error) {
263
189
  if (isDev()) {
264
190
  console.warn('Failed to synchronize sessions after switch:', error);
@@ -271,11 +197,12 @@ export const useSessionManagement = ({
271
197
 
272
198
  if (invalidSession) {
273
199
  // Server authority (`SessionClient` bootstrap/sync) reconciles which
274
- // account is actually active — just drop the invalid session from
275
- // the local view rather than guessing at a replacement.
276
- updateSessions(sessionsRef.current.filter((session) => session.sessionId !== sessionId), {
277
- merge: false,
278
- });
200
+ // account is actually active — just drop the invalid session from the
201
+ // local view rather than guessing at a replacement.
202
+ const remaining: ClientSession[] = runtimeRef.current
203
+ .getSnapshot()
204
+ .sessions.filter((session) => session.sessionId !== sessionId);
205
+ runtimeRef.current.mergeSessions(remaining, { merge: false });
279
206
  }
280
207
 
281
208
  handleAuthError(error, {
@@ -288,90 +215,14 @@ export const useSessionManagement = ({
288
215
  throw error instanceof Error ? error : new Error('Failed to switch session');
289
216
  }
290
217
  },
291
- [
292
- activateSession,
293
- logger,
294
- onError,
295
- oxyServices,
296
- setAuthError,
297
- updateSessions,
298
- ],
299
- );
300
-
301
- const refreshSessions = useCallback(
302
- async (activeUserId?: string): Promise<void> => {
303
- // Capture the active session id once so the async closure below uses a
304
- // narrowed, non-null local instead of re-reading the ref (which the
305
- // compiler cannot prove stays non-null across awaits).
306
- const activeSessionId = activeSessionIdRef.current;
307
- if (!activeSessionId) return;
308
-
309
- if (refreshInFlightRef.current) {
310
- await refreshInFlightRef.current;
311
- return;
312
- }
313
-
314
- const now = Date.now();
315
- if (now - lastRefreshRef.current < 500) {
316
- return;
317
- }
318
- lastRefreshRef.current = now;
319
-
320
- const refreshPromise = (async () => {
321
- try {
322
- const deviceSessions = await fetchSessionsWithFallback(oxyServices, activeSessionId, {
323
- fallbackUserId: activeUserId,
324
- logger,
325
- });
326
- updateSessions(deviceSessions, { merge: true });
327
- } catch (error) {
328
- if (isInvalidSessionError(error)) {
329
- // Server authority (`SessionClient` bootstrap/sync) reconciles
330
- // which account is actually active — just clear local state
331
- // rather than guessing at a replacement session.
332
- await clearSessionState();
333
- return;
334
- }
335
-
336
- handleAuthError(error, {
337
- defaultMessage: 'Failed to refresh sessions',
338
- code: 'SESSION_REFRESH_ERROR',
339
- onError,
340
- setAuthError,
341
- logger,
342
- });
343
- } finally {
344
- refreshInFlightRef.current = null;
345
- lastRefreshRef.current = Date.now();
346
- }
347
- })();
348
-
349
- refreshInFlightRef.current = refreshPromise;
350
- await refreshPromise;
351
- },
352
- [
353
- clearSessionState,
354
- logger,
355
- onError,
356
- oxyServices,
357
- setAuthError,
358
- updateSessions,
359
- ],
218
+ [logger, onAuthStateChange, onError, oxyServices, saveActiveSessionId, setAuthError],
360
219
  );
361
220
 
362
- const isRefreshInFlight = Boolean(refreshInFlightRef.current);
363
-
364
221
  return {
365
- sessions,
366
- activeSessionId,
367
- setActiveSessionId,
368
- updateSessions,
222
+ saveSessionIds,
223
+ saveActiveSessionId,
369
224
  switchSession,
370
- refreshSessions,
371
225
  clearSessionState,
372
- saveActiveSessionId,
373
- trackRemovedSession,
374
226
  storageKeys,
375
- isRefreshInFlight,
376
227
  };
377
228
  };
package/src/ui/index.ts CHANGED
@@ -29,7 +29,7 @@ export { default as OxyPayButton } from './components/OxyPayButton';
29
29
  export { default as ProfileButton } from './components/ProfileButton';
30
30
 
31
31
  // Context + hooks
32
- export { useOxy } from './context/OxyContext';
32
+ export { useOxy, useOptionalOxy, OxyProviderMissingError } from './context/OxyContext';
33
33
  export { useAuth } from './hooks/useAuth';
34
34
  export { useFollow, useSeedFollowStatuses } from './hooks/useFollow';
35
35
  export { useStorage } from './hooks/useStorage';
@@ -44,7 +44,6 @@ export { default as AccountSettingsScreen } from './screens/AccountSettingsScree
44
44
 
45
45
  // Stores
46
46
  export { useAuthStore } from './stores/authStore';
47
- export { useAccountStore } from './stores/accountStore';
48
47
 
49
48
  // Error handlers (pure functions)
50
49
  export {
@@ -1,10 +1,6 @@
1
- import type { ComponentType } from 'react';
1
+ import { lazy, type ComponentType } from 'react';
2
2
  import type { BaseScreenProps } from '../types/navigation';
3
3
 
4
- // Lazy loading: Screens are loaded on-demand to break require cycles
5
- // This prevents screens (which import OxyContext) from being loaded
6
- // before OxyContext is fully initialized
7
-
8
4
  // Define all available route names
9
5
  export type RouteName =
10
6
  | 'ManageAccount' // Unified "Manage your Oxy Account" surface
@@ -46,85 +42,99 @@ export type RouteName =
46
42
  | 'Preferences' // General user preferences (theme, reduce-motion, etc.)
47
43
  | 'AccountDialog'; // Unified account switcher + sign-in surface (OxyAccountDialogScreen body)
48
44
 
49
- // Lazy screen loaders - functions that return screen components on-demand
50
- // This breaks the require cycle by deferring imports until screens are actually needed
51
- const screenLoaders: Record<RouteName, () => ComponentType<BaseScreenProps>> = {
52
- ManageAccount: () => require('../screens/ManageAccountScreen').default,
53
- AccountVerification: () => require('../screens/AccountVerificationScreen').default,
54
- PaymentGateway: () => require('../screens/PaymentGatewayScreen').default,
55
- Profile: () => require('../screens/ProfileScreen').default,
56
- LanguageSelector: () => require('../screens/LanguageSelectorScreen').default,
57
- PrivacySettings: () => require('../screens/PrivacySettingsScreen').default,
58
- SearchSettings: () => require('../screens/SearchSettingsScreen').default,
59
- FileManagement: () => require('../screens/FileManagementScreen').default,
60
- HelpSupport: () => require('../screens/HelpSupportScreen').default,
61
- FAQ: () => require('../screens/FAQScreen').default,
62
- Feedback: () => require('../screens/FeedbackScreen').default,
63
- LegalDocuments: () => require('../screens/LegalDocumentsScreen').default,
64
- AppInfo: () => require('../screens/AppInfoScreen').default,
65
- PremiumSubscription: () => require('../screens/PremiumSubscriptionScreen').default,
66
- WelcomeNewUser: () => require('../screens/WelcomeNewUserScreen').default,
67
- UserLinks: () => require('../screens/UserLinksScreen').default,
68
- HistoryView: () => require('../screens/HistoryViewScreen').default,
69
- SavesCollections: () => require('../screens/SavesCollectionsScreen').default,
70
- EditProfile: () => require('../screens/EditProfileScreen').default,
71
- EditProfileField: () => require('../screens/EditProfileFieldScreen').default,
45
+ /**
46
+ * The component for each route, loaded on demand.
47
+ *
48
+ * Every entry is `lazy(() => import(...))`: the screen module is fetched and
49
+ * evaluated the first time its surface is presented, never at import time. That
50
+ * matters twice over — screens import `OxyContext`, which reaches back here, so
51
+ * eager evaluation would run screens mid-cycle; and it keeps native-only screen
52
+ * dependencies out of the evaluation path of every consumer that merely touches
53
+ * the SDK.
54
+ *
55
+ * What defers the load must NOT be `require()`. `@oxyhq/services` ships an ESM
56
+ * build, and a `require()` in ESM output forces web bundlers into CommonJS
57
+ * interop: rolldown-vite defers every module in the required subgraph behind a
58
+ * lazy initializer and then hands a consumer that statically imported one of
59
+ * them the still-`undefined` binding. That is how `OxySignInRequestSurface`
60
+ * reached auth.oxy.so/authorize as `undefined` and blanked the page with React
61
+ * error #130 — this registry pulled `OxyAccountDialogScreen`, and the whole
62
+ * sign-in surface subgraph with it, through `require()`.
63
+ *
64
+ * The value type is `ComponentType<never>`, which every screen satisfies. A few
65
+ * screens (`Profile`, `PaymentGateway`, `UserLinks`, `FollowersList`,
66
+ * `FollowingList`) declare props BEYOND {@link BaseScreenProps} — `userId`,
67
+ * `amount` — that only reach them through the route's untyped props bag
68
+ * (`present(route, props)`), so this map cannot prove they are satisfied. The
69
+ * previous `require()` returned `any` and hid that entirely; stating it here
70
+ * confines the gap to one documented widening in {@link getScreenComponent}.
71
+ */
72
+ const screenComponents: Record<RouteName, ComponentType<never>> = {
73
+ ManageAccount: lazy(() => import('../screens/ManageAccountScreen')),
74
+ AccountVerification: lazy(() => import('../screens/AccountVerificationScreen')),
75
+ PaymentGateway: lazy(() => import('../screens/PaymentGatewayScreen')),
76
+ Profile: lazy(() => import('../screens/ProfileScreen')),
77
+ LanguageSelector: lazy(() => import('../screens/LanguageSelectorScreen')),
78
+ PrivacySettings: lazy(() => import('../screens/PrivacySettingsScreen')),
79
+ SearchSettings: lazy(() => import('../screens/SearchSettingsScreen')),
80
+ FileManagement: lazy(() => import('../screens/FileManagementScreen')),
81
+ HelpSupport: lazy(() => import('../screens/HelpSupportScreen')),
82
+ FAQ: lazy(() => import('../screens/FAQScreen')),
83
+ Feedback: lazy(() => import('../screens/FeedbackScreen')),
84
+ LegalDocuments: lazy(() => import('../screens/LegalDocumentsScreen')),
85
+ AppInfo: lazy(() => import('../screens/AppInfoScreen')),
86
+ PremiumSubscription: lazy(() => import('../screens/PremiumSubscriptionScreen')),
87
+ WelcomeNewUser: lazy(() => import('../screens/WelcomeNewUserScreen')),
88
+ UserLinks: lazy(() => import('../screens/UserLinksScreen')),
89
+ HistoryView: lazy(() => import('../screens/HistoryViewScreen')),
90
+ SavesCollections: lazy(() => import('../screens/SavesCollectionsScreen')),
91
+ EditProfile: lazy(() => import('../screens/EditProfileScreen')),
92
+ EditProfileField: lazy(() => import('../screens/EditProfileFieldScreen')),
72
93
  // Informational screens
73
- LearnMoreUsernames: () => require('../screens/LearnMoreUsernamesScreen').default,
94
+ LearnMoreUsernames: lazy(() => import('../screens/LearnMoreUsernamesScreen')),
74
95
  // Oxy Trust screens
75
- TrustCenter: () => require('../screens/trust/TrustCenterScreen').default,
76
- TrustLeaderboard: () => require('../screens/trust/TrustLeaderboardScreen').default,
77
- TrustRewards: () => require('../screens/trust/TrustRewardsScreen').default,
78
- TrustRules: () => require('../screens/trust/TrustRulesScreen').default,
79
- AboutTrust: () => require('../screens/trust/TrustAboutScreen').default,
80
- TrustFAQ: () => require('../screens/trust/TrustFAQScreen').default,
96
+ TrustCenter: lazy(() => import('../screens/trust/TrustCenterScreen')),
97
+ TrustLeaderboard: lazy(() => import('../screens/trust/TrustLeaderboardScreen')),
98
+ TrustRewards: lazy(() => import('../screens/trust/TrustRewardsScreen')),
99
+ TrustRules: lazy(() => import('../screens/trust/TrustRulesScreen')),
100
+ AboutTrust: lazy(() => import('../screens/trust/TrustAboutScreen')),
101
+ TrustFAQ: lazy(() => import('../screens/trust/TrustFAQScreen')),
81
102
  // User list screens (followers/following)
82
- FollowersList: () => require('../screens/FollowersListScreen').default,
83
- FollowingList: () => require('../screens/FollowingListScreen').default,
84
- CreateAccount: () => require('../screens/CreateAccountScreen').default,
85
- AccountMembers: () => require('../screens/AccountMembersScreen').default,
86
- AccountSettings: () => require('../screens/AccountSettingsScreen').default,
87
- ChangeAvatar: () => require('../screens/ChangeAvatarScreen').default,
88
- AvatarCrop: () => require('../screens/AvatarCropScreen').default,
89
- Notifications: () => require('../screens/NotificationsScreen').default,
90
- ConnectedApps: () => require('../screens/ConnectedAppsScreen').default,
91
- Preferences: () => require('../screens/PreferencesScreen').default,
103
+ FollowersList: lazy(() => import('../screens/FollowersListScreen')),
104
+ FollowingList: lazy(() => import('../screens/FollowingListScreen')),
105
+ CreateAccount: lazy(() => import('../screens/CreateAccountScreen')),
106
+ AccountMembers: lazy(() => import('../screens/AccountMembersScreen')),
107
+ AccountSettings: lazy(() => import('../screens/AccountSettingsScreen')),
108
+ ChangeAvatar: lazy(() => import('../screens/ChangeAvatarScreen')),
109
+ AvatarCrop: lazy(() => import('../screens/AvatarCropScreen')),
110
+ Notifications: lazy(() => import('../screens/NotificationsScreen')),
111
+ ConnectedApps: lazy(() => import('../screens/ConnectedAppsScreen')),
112
+ Preferences: lazy(() => import('../screens/PreferencesScreen')),
92
113
  // Unified account switcher + sign-in surface. Its body lives in the
93
114
  // `OxyAccountDialogScreen` component (folded from the standalone dialog); the
94
115
  // surface stack provides the Dialog chrome around it.
95
- AccountDialog: () => require('../components/OxyAccountDialogScreen').default,
116
+ AccountDialog: lazy(() => import('../components/OxyAccountDialogScreen')),
96
117
  };
97
118
 
98
- // Cache loaded components to avoid re-requiring
99
- const screenCache = new Map<RouteName, ComponentType<BaseScreenProps>>();
100
-
101
- // Helper function to get a screen component by route name (lazy loaded)
102
- export const getScreenComponent = (routeName: RouteName): ComponentType<BaseScreenProps> | undefined => {
103
- // Return cached component if available
104
- if (screenCache.has(routeName)) {
105
- return screenCache.get(routeName);
106
- }
107
-
108
- // Lazy load the component
109
- const loader = screenLoaders[routeName];
110
- if (loader) {
111
- try {
112
- const component = loader();
113
- screenCache.set(routeName, component);
114
- return component;
115
- } catch (error) {
116
- if (__DEV__) {
117
- console.error(`[Routes] Failed to load screen: ${routeName}`, error);
118
- }
119
- return undefined;
120
- }
121
- }
122
-
123
- return undefined;
124
- };
119
+ /**
120
+ * Resolve the component for a route.
121
+ *
122
+ * The map is total over {@link RouteName} the compiler enforces that at its
123
+ * declaration so this returns `undefined` only for a caller that reached here
124
+ * with an unchecked string; {@link isValidRoute} is how such a caller narrows.
125
+ *
126
+ * The surface host renders the result with {@link BaseScreenProps} merged with
127
+ * the route's own props bag, so that is the type it is handed back as. This one
128
+ * widening is where the gap documented on {@link screenComponents} lives: the map
129
+ * dispatches on a string key, so a screen's extra prop requirements are met at
130
+ * `present(route, props)` call sites, not provable here. No caching is needed —
131
+ * React memoizes each `lazy()` component's module after its first load.
132
+ */
133
+ export const getScreenComponent = (routeName: RouteName): ComponentType<BaseScreenProps> | undefined =>
134
+ screenComponents[routeName] as ComponentType<BaseScreenProps>;
125
135
 
126
136
  // Helper function to check if a route exists
127
- // Uses the screenLoaders object to check existence without loading the screen
137
+ // Uses the screenComponents map to check existence without loading the screen
128
138
  export const isValidRoute = (routeName: string): routeName is RouteName => {
129
- return routeName in screenLoaders;
139
+ return routeName in screenComponents;
130
140
  };
@@ -13,6 +13,7 @@ import {
13
13
  type SurfaceRouteConfig,
14
14
  } from './surfaceRegistry';
15
15
  import { createSurfaceNavStack, type SurfaceNavStack } from './surfaceNavStack';
16
+ import SurfaceScreen from '../components/SurfaceScreen';
16
17
 
17
18
  /**
18
19
  * The SDK's typed surface API — a route registry layered on top of Bloom's
@@ -153,15 +154,11 @@ function presentInternal<K extends RouteName>(
153
154
  const config = getSurfaceConfig(route, props);
154
155
  const bloomOpts: PresentOptions = { label: route, ...bloomOptionsFor(config), ...opts };
155
156
 
156
- // Lazy-resolved to break the surfaces.ts <-> SurfaceScreen module cycle: a
157
- // mounted SurfaceScreen presents further surfaces (it imports these presenters),
158
- // while presenting one renders a SurfaceScreen. Deferring the component to call
159
- // time (both modules are initialized by then) makes the import graph one-way —
160
- // the same idiom `routes.ts` uses to lazy-load screen components.
161
- const SurfaceScreen = (
162
- require('../components/SurfaceScreen') as typeof import('../components/SurfaceScreen')
163
- ).default;
164
-
157
+ // `SurfaceScreen` is statically imported but only READ here, at presentation
158
+ // time. That keeps the surfaces.ts <-> SurfaceScreen cycle safe (a mounted
159
+ // SurfaceScreen imports these presenters, while presenting one renders a
160
+ // SurfaceScreen) without a `require()` which ESM output must never contain,
161
+ // see the note on `screenComponents` in `./routes`.
165
162
  const result = bloomSurfaces.present<SurfaceResult<K>>((surface: SurfaceControls) =>
166
163
  createElement(SurfaceScreen, {
167
164
  navStack,