@oxyhq/services 13.3.0 → 14.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 (251) hide show
  1. package/lib/commonjs/index.js +11 -17
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/AccountMenu.js +103 -65
  4. package/lib/commonjs/ui/components/AccountMenu.js.map +1 -1
  5. package/lib/commonjs/ui/components/AccountSwitcher.js +84 -126
  6. package/lib/commonjs/ui/components/AccountSwitcher.js.map +1 -1
  7. package/lib/commonjs/ui/components/ProfileMenu.js +140 -153
  8. package/lib/commonjs/ui/components/ProfileMenu.js.map +1 -1
  9. package/lib/commonjs/ui/components/SignInModal.js +4 -4
  10. package/lib/commonjs/ui/components/SignInModal.js.map +1 -1
  11. package/lib/commonjs/ui/context/OxyContext.js +506 -466
  12. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  13. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +59 -57
  14. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  15. package/lib/commonjs/ui/context/inSessionTokenRefresh.js +23 -42
  16. package/lib/commonjs/ui/context/inSessionTokenRefresh.js.map +1 -1
  17. package/lib/commonjs/ui/context/silentSessionRestore.js +12 -21
  18. package/lib/commonjs/ui/context/silentSessionRestore.js.map +1 -1
  19. package/lib/commonjs/ui/hooks/useAuth.js +4 -3
  20. package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
  21. package/lib/commonjs/ui/hooks/useOxyAuthSession.js +12 -7
  22. package/lib/commonjs/ui/hooks/useOxyAuthSession.js.map +1 -1
  23. package/lib/commonjs/ui/hooks/useSessionManagement.js +17 -65
  24. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  25. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +288 -0
  26. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -0
  27. package/lib/commonjs/ui/hooks/useWebSSO.js +12 -191
  28. package/lib/commonjs/ui/hooks/useWebSSO.js.map +1 -1
  29. package/lib/commonjs/ui/index.js.map +1 -1
  30. package/lib/commonjs/ui/screens/OxyAuthScreen.js +2 -2
  31. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  32. package/lib/commonjs/ui/session/createSessionClient.js +28 -0
  33. package/lib/commonjs/ui/session/createSessionClient.js.map +1 -0
  34. package/lib/commonjs/ui/session/index.js +52 -0
  35. package/lib/commonjs/ui/session/index.js.map +1 -0
  36. package/lib/commonjs/ui/session/projectSessionState.js +86 -0
  37. package/lib/commonjs/ui/session/projectSessionState.js.map +1 -0
  38. package/lib/commonjs/ui/session/sessionClientHost.js +30 -0
  39. package/lib/commonjs/ui/session/sessionClientHost.js.map +1 -0
  40. package/lib/commonjs/ui/session/tokenTransport.js +77 -0
  41. package/lib/commonjs/ui/session/tokenTransport.js.map +1 -0
  42. package/lib/commonjs/ui/utils/activeAuthuser.js +35 -79
  43. package/lib/commonjs/ui/utils/activeAuthuser.js.map +1 -1
  44. package/lib/commonjs/ui/utils/sessionHelpers.js +1 -51
  45. package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
  46. package/lib/commonjs/utils/deviceFlowSignIn.js +70 -15
  47. package/lib/commonjs/utils/deviceFlowSignIn.js.map +1 -1
  48. package/lib/module/index.js +5 -5
  49. package/lib/module/index.js.map +1 -1
  50. package/lib/module/ui/components/AccountMenu.js +103 -65
  51. package/lib/module/ui/components/AccountMenu.js.map +1 -1
  52. package/lib/module/ui/components/AccountSwitcher.js +85 -127
  53. package/lib/module/ui/components/AccountSwitcher.js.map +1 -1
  54. package/lib/module/ui/components/ProfileMenu.js +143 -156
  55. package/lib/module/ui/components/ProfileMenu.js.map +1 -1
  56. package/lib/module/ui/components/SignInModal.js +4 -4
  57. package/lib/module/ui/components/SignInModal.js.map +1 -1
  58. package/lib/module/ui/context/OxyContext.js +510 -470
  59. package/lib/module/ui/context/OxyContext.js.map +1 -1
  60. package/lib/module/ui/context/hooks/useAuthOperations.js +61 -60
  61. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  62. package/lib/module/ui/context/inSessionTokenRefresh.js +24 -43
  63. package/lib/module/ui/context/inSessionTokenRefresh.js.map +1 -1
  64. package/lib/module/ui/context/silentSessionRestore.js +12 -20
  65. package/lib/module/ui/context/silentSessionRestore.js.map +1 -1
  66. package/lib/module/ui/hooks/useAuth.js +4 -3
  67. package/lib/module/ui/hooks/useAuth.js.map +1 -1
  68. package/lib/module/ui/hooks/useOxyAuthSession.js +12 -7
  69. package/lib/module/ui/hooks/useOxyAuthSession.js.map +1 -1
  70. package/lib/module/ui/hooks/useSessionManagement.js +18 -66
  71. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  72. package/lib/module/ui/hooks/useSwitchableAccounts.js +283 -0
  73. package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -0
  74. package/lib/module/ui/hooks/useWebSSO.js +13 -192
  75. package/lib/module/ui/hooks/useWebSSO.js.map +1 -1
  76. package/lib/module/ui/index.js +0 -1
  77. package/lib/module/ui/index.js.map +1 -1
  78. package/lib/module/ui/screens/OxyAuthScreen.js +2 -2
  79. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  80. package/lib/module/ui/session/createSessionClient.js +25 -0
  81. package/lib/module/ui/session/createSessionClient.js.map +1 -0
  82. package/lib/module/ui/session/index.js +17 -0
  83. package/lib/module/ui/session/index.js.map +1 -0
  84. package/lib/module/ui/session/projectSessionState.js +79 -0
  85. package/lib/module/ui/session/projectSessionState.js.map +1 -0
  86. package/lib/module/ui/session/sessionClientHost.js +26 -0
  87. package/lib/module/ui/session/sessionClientHost.js.map +1 -0
  88. package/lib/module/ui/session/tokenTransport.js +74 -0
  89. package/lib/module/ui/session/tokenTransport.js.map +1 -0
  90. package/lib/module/ui/utils/activeAuthuser.js +34 -76
  91. package/lib/module/ui/utils/activeAuthuser.js.map +1 -1
  92. package/lib/module/ui/utils/sessionHelpers.js +0 -49
  93. package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
  94. package/lib/module/utils/deviceFlowSignIn.js +71 -16
  95. package/lib/module/utils/deviceFlowSignIn.js.map +1 -1
  96. package/lib/typescript/commonjs/index.d.ts +2 -3
  97. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +4 -2
  99. package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts +7 -8
  101. package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +1 -1
  102. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +12 -9
  103. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +1 -1
  104. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +16 -13
  105. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  106. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +27 -3
  107. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts +22 -17
  109. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts.map +1 -1
  110. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts +12 -18
  111. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts.map +1 -1
  112. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +1 -0
  113. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts +1 -1
  115. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
  116. package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts +2 -2
  117. package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts.map +1 -1
  118. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +162 -0
  120. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts +13 -52
  122. package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  124. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +15 -0
  125. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -0
  126. package/lib/typescript/commonjs/ui/session/index.d.ts +15 -0
  127. package/lib/typescript/commonjs/ui/session/index.d.ts.map +1 -0
  128. package/lib/typescript/commonjs/ui/session/projectSessionState.d.ts +45 -0
  129. package/lib/typescript/commonjs/ui/session/projectSessionState.d.ts.map +1 -0
  130. package/lib/typescript/commonjs/ui/session/sessionClientHost.d.ts +14 -0
  131. package/lib/typescript/commonjs/ui/session/sessionClientHost.d.ts.map +1 -0
  132. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts +24 -0
  133. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts.map +1 -0
  134. package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts +21 -29
  135. package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts.map +1 -1
  136. package/lib/typescript/commonjs/ui/utils/sessionHelpers.d.ts +0 -19
  137. package/lib/typescript/commonjs/ui/utils/sessionHelpers.d.ts.map +1 -1
  138. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +51 -19
  139. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +1 -1
  140. package/lib/typescript/module/index.d.ts +2 -3
  141. package/lib/typescript/module/index.d.ts.map +1 -1
  142. package/lib/typescript/module/ui/components/AccountMenu.d.ts +4 -2
  143. package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +1 -1
  144. package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +7 -8
  145. package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +1 -1
  146. package/lib/typescript/module/ui/components/ProfileMenu.d.ts +12 -9
  147. package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +1 -1
  148. package/lib/typescript/module/ui/context/OxyContext.d.ts +16 -13
  149. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  150. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +27 -3
  151. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  152. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts +22 -17
  153. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts.map +1 -1
  154. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts +12 -18
  155. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts.map +1 -1
  156. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +1 -0
  157. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  158. package/lib/typescript/module/ui/hooks/useAuth.d.ts +1 -1
  159. package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
  160. package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts +2 -2
  161. package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts.map +1 -1
  162. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
  163. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +162 -0
  164. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -0
  165. package/lib/typescript/module/ui/hooks/useWebSSO.d.ts +13 -52
  166. package/lib/typescript/module/ui/hooks/useWebSSO.d.ts.map +1 -1
  167. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  168. package/lib/typescript/module/ui/session/createSessionClient.d.ts +15 -0
  169. package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -0
  170. package/lib/typescript/module/ui/session/index.d.ts +15 -0
  171. package/lib/typescript/module/ui/session/index.d.ts.map +1 -0
  172. package/lib/typescript/module/ui/session/projectSessionState.d.ts +45 -0
  173. package/lib/typescript/module/ui/session/projectSessionState.d.ts.map +1 -0
  174. package/lib/typescript/module/ui/session/sessionClientHost.d.ts +14 -0
  175. package/lib/typescript/module/ui/session/sessionClientHost.d.ts.map +1 -0
  176. package/lib/typescript/module/ui/session/tokenTransport.d.ts +24 -0
  177. package/lib/typescript/module/ui/session/tokenTransport.d.ts.map +1 -0
  178. package/lib/typescript/module/ui/utils/activeAuthuser.d.ts +21 -29
  179. package/lib/typescript/module/ui/utils/activeAuthuser.d.ts.map +1 -1
  180. package/lib/typescript/module/ui/utils/sessionHelpers.d.ts +0 -19
  181. package/lib/typescript/module/ui/utils/sessionHelpers.d.ts.map +1 -1
  182. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +51 -19
  183. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +1 -1
  184. package/package.json +4 -4
  185. package/src/index.ts +9 -9
  186. package/src/ui/components/AccountMenu.tsx +117 -70
  187. package/src/ui/components/AccountSwitcher.tsx +88 -134
  188. package/src/ui/components/ProfileMenu.tsx +158 -162
  189. package/src/ui/components/SignInModal.tsx +5 -5
  190. package/src/ui/context/OxyContext.tsx +560 -475
  191. package/src/ui/context/hooks/useAuthOperations.ts +72 -63
  192. package/src/ui/context/inSessionTokenRefresh.ts +23 -42
  193. package/src/ui/context/silentSessionRestore.ts +12 -26
  194. package/src/ui/hooks/useAuth.ts +4 -3
  195. package/src/ui/hooks/useOxyAuthSession.ts +13 -8
  196. package/src/ui/hooks/useSessionManagement.ts +16 -87
  197. package/src/ui/hooks/useSwitchableAccounts.ts +397 -0
  198. package/src/ui/hooks/useWebSSO.ts +13 -227
  199. package/src/ui/index.ts +0 -1
  200. package/src/ui/screens/OxyAuthScreen.tsx +2 -2
  201. package/src/ui/session/__tests__/createSessionClient.test.ts +41 -0
  202. package/src/ui/session/__tests__/projectSessionState.test.ts +114 -0
  203. package/src/ui/session/__tests__/sessionClientHost.test.ts +43 -0
  204. package/src/ui/session/__tests__/tokenTransport.test.ts +142 -0
  205. package/src/ui/session/createSessionClient.ts +21 -0
  206. package/src/ui/session/index.ts +19 -0
  207. package/src/ui/session/projectSessionState.ts +85 -0
  208. package/src/ui/session/sessionClientHost.ts +27 -0
  209. package/src/ui/session/tokenTransport.ts +76 -0
  210. package/src/ui/utils/activeAuthuser.ts +34 -76
  211. package/src/ui/utils/sessionHelpers.ts +0 -66
  212. package/src/utils/__tests__/deviceFlowSignIn.test.ts +243 -34
  213. package/src/utils/deviceFlowSignIn.ts +98 -21
  214. package/lib/commonjs/ui/components/accountMenuRows.js +0 -33
  215. package/lib/commonjs/ui/components/accountMenuRows.js.map +0 -1
  216. package/lib/commonjs/ui/hooks/useDeviceAccounts.js +0 -280
  217. package/lib/commonjs/ui/hooks/useDeviceAccounts.js.map +0 -1
  218. package/lib/commonjs/ui/hooks/useSessionSocket.js +0 -203
  219. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +0 -1
  220. package/lib/commonjs/utils/silentGuardKey.js +0 -54
  221. package/lib/commonjs/utils/silentGuardKey.js.map +0 -1
  222. package/lib/module/ui/components/accountMenuRows.js +0 -29
  223. package/lib/module/ui/components/accountMenuRows.js.map +0 -1
  224. package/lib/module/ui/hooks/useDeviceAccounts.js +0 -276
  225. package/lib/module/ui/hooks/useDeviceAccounts.js.map +0 -1
  226. package/lib/module/ui/hooks/useSessionSocket.js +0 -199
  227. package/lib/module/ui/hooks/useSessionSocket.js.map +0 -1
  228. package/lib/module/utils/silentGuardKey.js +0 -49
  229. package/lib/module/utils/silentGuardKey.js.map +0 -1
  230. package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts +0 -34
  231. package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts.map +0 -1
  232. package/lib/typescript/commonjs/ui/hooks/useDeviceAccounts.d.ts +0 -133
  233. package/lib/typescript/commonjs/ui/hooks/useDeviceAccounts.d.ts.map +0 -1
  234. package/lib/typescript/commonjs/ui/hooks/useSessionSocket.d.ts +0 -14
  235. package/lib/typescript/commonjs/ui/hooks/useSessionSocket.d.ts.map +0 -1
  236. package/lib/typescript/commonjs/utils/silentGuardKey.d.ts +0 -31
  237. package/lib/typescript/commonjs/utils/silentGuardKey.d.ts.map +0 -1
  238. package/lib/typescript/module/ui/components/accountMenuRows.d.ts +0 -34
  239. package/lib/typescript/module/ui/components/accountMenuRows.d.ts.map +0 -1
  240. package/lib/typescript/module/ui/hooks/useDeviceAccounts.d.ts +0 -133
  241. package/lib/typescript/module/ui/hooks/useDeviceAccounts.d.ts.map +0 -1
  242. package/lib/typescript/module/ui/hooks/useSessionSocket.d.ts +0 -14
  243. package/lib/typescript/module/ui/hooks/useSessionSocket.d.ts.map +0 -1
  244. package/lib/typescript/module/utils/silentGuardKey.d.ts +0 -31
  245. package/lib/typescript/module/utils/silentGuardKey.d.ts.map +0 -1
  246. package/src/ui/components/accountMenuRows.ts +0 -48
  247. package/src/ui/hooks/useDeviceAccounts.ts +0 -344
  248. package/src/ui/hooks/useSessionSocket.ts +0 -233
  249. package/src/ui/utils/__tests__/activeAuthuser.test.ts +0 -75
  250. package/src/utils/__tests__/silentGuardKey.test.ts +0 -82
  251. package/src/utils/silentGuardKey.ts +0 -46
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+
3
+ import { useMemo } from 'react';
4
+ import { useQuery } from '@tanstack/react-query';
5
+ import { getAccountDisplayName, getAccountFallbackHandle } from '@oxyhq/core';
6
+ import { useOxy } from "../context/OxyContext.js";
7
+ import { useI18n } from "./useI18n.js";
8
+ import { queryKeys } from "./queries/queryKeys.js";
9
+
10
+ /**
11
+ * The per-account user shape carried by a {@link SwitchableAccount}. The SDK's
12
+ * canonical {@link User} document — either the freshest `useOxy().user` (the
13
+ * active row), a profile resolved via `oxyServices.getUsersByIds()` (every other
14
+ * device row), or the `account` document embedded in an account-graph node.
15
+ */
16
+
17
+ /**
18
+ * One account the signed-in user can switch INTO, in the uniform switch model.
19
+ *
20
+ * A switchable account is either a device sign-in, an account-graph node (owned
21
+ * org / shared-with-you), or BOTH (an account that has been switched into
22
+ * becomes a device session while still being a graph node — the two are deduped
23
+ * into a single row). Every row carries a canonical `accountId` (the uniform
24
+ * switch key passed to `switchToAccount`); `sessionId` is present IFF the
25
+ * account is currently signed in on THIS device.
26
+ */
27
+
28
+ /** The minimal device-session shape {@link buildSwitchableAccounts} reads. */
29
+
30
+ /**
31
+ * Resolve which entries are the current account, robustly.
32
+ *
33
+ * Primary signal: `entry.sessionId === activeSessionId` — both are projected
34
+ * from the same `SessionClient` state, so this normally matches exactly.
35
+ * Fallbacks exist only to bridge the brief window between the two sequential
36
+ * `updateSessions` / `setActiveSessionId` calls in `OxyContext.syncFromClient`,
37
+ * applied only when the `sessionId` match found nothing AND the user is
38
+ * authenticated:
39
+ * 1. Match the live `user.id` against each entry's per-account user id.
40
+ * 2. If still nothing and there is exactly one account, mark that one current.
41
+ *
42
+ * At most ONE entry is ever marked current. Runs over DEVICE rows only (graph
43
+ * rows are never active — the active account is always a device session), so the
44
+ * single-account fallback counts device rows.
45
+ *
46
+ * Pure & side-effect free so it is unit-testable without rendering React.
47
+ */
48
+ export function markCurrentAccount(accounts, activeSessionId, liveUserId, isAuthenticated) {
49
+ const bySession = accounts.map(account => ({
50
+ ...account,
51
+ isCurrent: Boolean(activeSessionId) && account.sessionId === activeSessionId
52
+ }));
53
+ if (bySession.some(account => account.isCurrent) || !isAuthenticated) {
54
+ return bySession;
55
+ }
56
+
57
+ // No row matched by session id: fall back to the live user's id, marking at
58
+ // most the FIRST matching entry current (never more than one).
59
+ if (liveUserId) {
60
+ let matched = false;
61
+ const byUser = bySession.map(account => {
62
+ if (!matched && account.user.id === liveUserId) {
63
+ matched = true;
64
+ return {
65
+ ...account,
66
+ isCurrent: true
67
+ };
68
+ }
69
+ return account;
70
+ });
71
+ if (matched) {
72
+ return byUser;
73
+ }
74
+ }
75
+
76
+ // Authenticated, nothing matched, but there is exactly one account → it must
77
+ // be the current one.
78
+ if (bySession.length === 1) {
79
+ return [{
80
+ ...bySession[0],
81
+ isCurrent: true
82
+ }];
83
+ }
84
+ return bySession;
85
+ }
86
+
87
+ /**
88
+ * Pure union of device sign-ins and account-graph nodes into the flat
89
+ * {@link SwitchableAccount}[] the switchers render. Extracted so the merge /
90
+ * dedup semantics are unit-testable without rendering React.
91
+ *
92
+ * Order: device rows first (in session order, current flagged), then graph-only
93
+ * rows (in graph order). An account present as BOTH a device session and a graph
94
+ * node is deduped into ONE device row enriched with the graph metadata
95
+ * (relationship / kind / parent / membership).
96
+ */
97
+ export function buildSwitchableAccounts(input) {
98
+ const {
99
+ sessions,
100
+ activeSessionId,
101
+ liveUser,
102
+ isAuthenticated,
103
+ graph,
104
+ profilesById,
105
+ locale,
106
+ resolveAvatarUrl
107
+ } = input;
108
+
109
+ // Nothing is switchable when signed out — never surface a lingering device
110
+ // session or graph node once the user is unauthenticated.
111
+ if (!isAuthenticated) {
112
+ return [];
113
+ }
114
+ const toRow = (accountUser, opts) => {
115
+ const displayName = getAccountDisplayName(accountUser, locale);
116
+ const handle = getAccountFallbackHandle(accountUser);
117
+ const secondaryHandle = handle ? `@${handle}` : null;
118
+ return {
119
+ accountId: accountUser.id?.toString() ?? '',
120
+ sessionId: opts.sessionId,
121
+ authuser: opts.authuser,
122
+ isCurrent: Boolean(opts.sessionId) && opts.sessionId === activeSessionId,
123
+ onDevice: Boolean(opts.sessionId),
124
+ relationship: opts.relationship,
125
+ kind: opts.kind,
126
+ parentAccountId: opts.parentAccountId,
127
+ callerMembership: opts.callerMembership,
128
+ displayName,
129
+ // Real email, or the `@handle` fallback (NEVER synthesized).
130
+ email: accountUser.email ?? secondaryHandle,
131
+ avatarUrl: resolveAvatarUrl(accountUser.avatar),
132
+ color: accountUser.color ?? null,
133
+ user: accountUser
134
+ };
135
+ };
136
+
137
+ // --- Device rows ---
138
+ const built = sessions.flatMap(session => {
139
+ const isCurrent = session.sessionId === activeSessionId;
140
+ // The active row always uses the live `user` — freshest available —
141
+ // regardless of whether the batch profile fetch has resolved yet.
142
+ const accountUser = isCurrent && liveUser ? liveUser : session.userId ? profilesById.get(session.userId) : undefined;
143
+ if (!accountUser) {
144
+ return [];
145
+ }
146
+ return [toRow(accountUser, {
147
+ sessionId: session.sessionId,
148
+ authuser: session.authuser
149
+ })];
150
+ });
151
+ const flagged = markCurrentAccount(built, activeSessionId, liveUser?.id ?? null, isAuthenticated);
152
+
153
+ // The signed-in user must ALWAYS be represented, even before the device
154
+ // session set has synced (e.g. immediately after cold boot). Synthesize a
155
+ // single current row from the live `useOxy().user` in that case.
156
+ const deviceRows = flagged.length === 0 && isAuthenticated && liveUser && activeSessionId ? [toRow(liveUser, {
157
+ sessionId: activeSessionId
158
+ })] : flagged;
159
+
160
+ // --- Merge graph nodes, deduping by account id ---
161
+ const byAccountId = new Map();
162
+ const order = [];
163
+ const remember = row => {
164
+ if (!row.accountId || byAccountId.has(row.accountId)) {
165
+ return;
166
+ }
167
+ byAccountId.set(row.accountId, row);
168
+ order.push(row.accountId);
169
+ };
170
+ for (const row of deviceRows) {
171
+ remember(row);
172
+ }
173
+ for (const node of graph) {
174
+ const existing = byAccountId.get(node.accountId);
175
+ if (existing) {
176
+ // On-device account that is ALSO in the graph: enrich the device row
177
+ // with graph metadata; keep its (freshest) profile + sessionId.
178
+ byAccountId.set(node.accountId, {
179
+ ...existing,
180
+ relationship: node.relationship,
181
+ kind: node.kind,
182
+ parentAccountId: node.parentAccountId,
183
+ callerMembership: node.callerMembership
184
+ });
185
+ continue;
186
+ }
187
+ // Graph-only account (owned org / shared, not yet a device session).
188
+ remember(toRow(node.account, {
189
+ relationship: node.relationship,
190
+ kind: node.kind,
191
+ parentAccountId: node.parentAccountId,
192
+ callerMembership: node.callerMembership
193
+ }));
194
+ }
195
+ return order.flatMap(id => {
196
+ const row = byAccountId.get(id);
197
+ return row ? [row] : [];
198
+ });
199
+ }
200
+
201
+ /**
202
+ * Resolve every account the signed-in user can switch into — device sign-ins
203
+ * AND linked graph accounts (owned orgs + shared-with-you) — as one flat list
204
+ * with real per-account name / email / avatar / color, deduped by account id.
205
+ *
206
+ * ## Data sources
207
+ *
208
+ * - Device sign-ins: `useOxy().sessions` — a `ClientSession[]` projected by
209
+ * `OxyContext.syncFromClient` from the server-authoritative `SessionClient`.
210
+ * Each session carries only `sessionId` + `userId`, so this hook additionally
211
+ * fetches every device account's profile via `oxyServices.getUsersByIds()`.
212
+ * The ACTIVE row always uses `useOxy().user` directly (the freshest copy).
213
+ * - Linked accounts: `useOxy().accounts` — the `AccountNode[]` graph the context
214
+ * loads from `GET /accounts`. Each node already embeds its `account` `User`
215
+ * document, so graph-only rows need no extra fetch.
216
+ *
217
+ * An account present as BOTH a device session and a graph node is deduped into
218
+ * ONE row (see {@link buildSwitchableAccounts}). EVERY row switches the same
219
+ * way — through `useOxy().switchToAccount(row.accountId)`.
220
+ *
221
+ * ## Error handling
222
+ *
223
+ * `getUsersByIds()` resolves to `[]` on a failed chunk (logged internally)
224
+ * rather than throwing. Device accounts whose profile could not be resolved are
225
+ * omitted until a subsequent fetch succeeds (except the active one, which never
226
+ * depends on this fetch); graph accounts are unaffected.
227
+ */
228
+ export function useSwitchableAccounts() {
229
+ const {
230
+ oxyServices,
231
+ sessions,
232
+ activeSessionId,
233
+ user,
234
+ isAuthenticated,
235
+ accounts: graph
236
+ } = useOxy();
237
+ const {
238
+ locale
239
+ } = useI18n();
240
+
241
+ // Every distinct account id carried by the device's session set, sorted for
242
+ // a stable query key regardless of session ordering.
243
+ const accountIds = useMemo(() => {
244
+ const ids = new Set();
245
+ for (const session of sessions ?? []) {
246
+ if (session.userId) {
247
+ ids.add(session.userId);
248
+ }
249
+ }
250
+ return Array.from(ids).sort();
251
+ }, [sessions]);
252
+ const profilesQuery = useQuery({
253
+ queryKey: queryKeys.users.list(accountIds),
254
+ queryFn: () => oxyServices.getUsersByIds(accountIds),
255
+ enabled: isAuthenticated && accountIds.length > 0,
256
+ staleTime: 5 * 60 * 1000,
257
+ // 5 minutes — matches useUserProfile's convention
258
+ gcTime: 30 * 60 * 1000 // 30 minutes
259
+ });
260
+ const profilesById = useMemo(() => {
261
+ const map = new Map();
262
+ for (const profile of profilesQuery.data ?? []) {
263
+ map.set(profile.id, profile);
264
+ }
265
+ return map;
266
+ }, [profilesQuery.data]);
267
+ const accounts = useMemo(() => buildSwitchableAccounts({
268
+ sessions: sessions ?? [],
269
+ activeSessionId: activeSessionId ?? null,
270
+ liveUser: user ?? null,
271
+ isAuthenticated,
272
+ graph: graph ?? [],
273
+ profilesById,
274
+ locale,
275
+ resolveAvatarUrl: avatar => avatar ? oxyServices.getFileDownloadUrl(avatar, 'thumb') : undefined
276
+ }), [sessions, activeSessionId, user, isAuthenticated, graph, profilesById, locale, oxyServices]);
277
+ return {
278
+ accounts,
279
+ isLoading: isAuthenticated && accountIds.length > 0 && profilesQuery.isLoading,
280
+ currentSessionId: activeSessionId ?? null
281
+ };
282
+ }
283
+ //# sourceMappingURL=useSwitchableAccounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useMemo","useQuery","getAccountDisplayName","getAccountFallbackHandle","useOxy","useI18n","queryKeys","markCurrentAccount","accounts","activeSessionId","liveUserId","isAuthenticated","bySession","map","account","isCurrent","Boolean","sessionId","some","matched","byUser","user","id","length","buildSwitchableAccounts","input","sessions","liveUser","graph","profilesById","locale","resolveAvatarUrl","toRow","accountUser","opts","displayName","handle","secondaryHandle","accountId","toString","authuser","onDevice","relationship","kind","parentAccountId","callerMembership","email","avatarUrl","avatar","color","built","flatMap","session","userId","get","undefined","flagged","deviceRows","byAccountId","Map","order","remember","row","has","set","push","node","existing","useSwitchableAccounts","oxyServices","accountIds","ids","Set","add","Array","from","sort","profilesQuery","queryKey","users","list","queryFn","getUsersByIds","enabled","staleTime","gcTime","profile","data","getFileDownloadUrl","isLoading","currentSessionId"],"sourceRoot":"../../../../src","sources":["ui/hooks/useSwitchableAccounts.ts"],"mappings":"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","ignoreList":[]}
@@ -1,203 +1,24 @@
1
1
  "use strict";
2
2
 
3
3
  /**
4
- * Web SSO Hook
5
- *
6
- * Handles cross-domain SSO for web apps using FedCM (Federated Credential Management).
7
- *
8
- * FedCM is the modern, privacy-preserving standard for cross-domain identity federation.
9
- * It works across completely different TLDs (alia.onl, mention.earth, homiio.com, etc.)
10
- * without relying on third-party cookies.
11
- *
12
- * For browsers without FedCM support, users will need to click a sign-in button
13
- * which triggers redirect authentication.
14
- *
15
- * This is called automatically by OxyContext on web platforms.
16
- *
17
- * @see https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API
4
+ * Platform detection helper for the web auth/session-sync surfaces.
5
+ *
6
+ * This module previously hosted a FedCM-based `useWebSSO` hook (Federated
7
+ * Credential Management — Chrome-only). It was removed: FedCM is no longer
8
+ * used anywhere in the client sign-in/cold-boot path (see `CrossDomainAuth`'s
9
+ * doc comment in `@oxyhq/core` for the production sign-in loop that motivated
10
+ * the removal). Cross-domain silent SSO is owned entirely by the
11
+ * `silent-iframe` cold-boot step (per-apex `/auth/silent`) plus the terminal
12
+ * `/sso` bounce in `OxyContext`.
13
+ *
14
+ * `isWebBrowser` is kept here (rather than moved) so every existing consumer
15
+ * import path stays valid.
18
16
  */
19
17
 
20
- import { useEffect, useRef, useCallback } from 'react';
21
- import { buildSilentGuardKey } from "../../utils/silentGuardKey.js";
22
- /**
23
- * Module-level guard tracking which (origin + API) signatures have already
24
- * had a silent SSO attempt this page load.
25
- *
26
- * A per-component `useRef` guard resets whenever the provider remounts (route
27
- * churn, StrictMode double-invoke, error-boundary recovery), which previously
28
- * allowed silent SSO to re-fire and — combined with a routing redirect loop —
29
- * produced an accelerating `navigator.credentials.get` retry storm. Keying the
30
- * guard on a stable signature instead of the component instance makes silent
31
- * SSO fire EXACTLY ONCE per page load regardless of how many times the
32
- * provider mounts. The set is intentionally never cleared: a fresh page load
33
- * (the only thing that can change the answer) starts a fresh module scope.
34
- */
35
- const silentSSOAttempted = new Set();
36
-
37
- /**
38
- * Build a stable signature for the silent-SSO run-once guard. Two providers
39
- * pointed at the same API from the same origin share one attempt.
40
- */
41
- function ssoSignature(oxyServices) {
42
- // Shared with `OxyContext.silentColdBootKey`. `buildSilentGuardKey` reads
43
- // `window.location.origin` behind a guard that also verifies
44
- // `window.location` exists — React Native aliases a global `window` with NO
45
- // `window.location`, so a `typeof window`-only check would throw
46
- // `Cannot read property 'origin' of undefined` off-browser.
47
- return buildSilentGuardKey(() => oxyServices.getBaseURL?.());
48
- }
49
-
50
18
  /**
51
19
  * Check if we're running in a web browser environment (not React Native)
52
20
  */
53
- function isWebBrowser() {
21
+ export function isWebBrowser() {
54
22
  return typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.documentElement !== 'undefined';
55
23
  }
56
-
57
- /**
58
- * Check if we're on the identity provider domain (where FedCM would authenticate against itself)
59
- * Compares against config.authWebUrl if set, otherwise defaults to auth.oxy.so
60
- */
61
- function isIdentityProvider(authWebUrl) {
62
- if (!isWebBrowser()) return false;
63
- const hostname = window.location.hostname;
64
- let idpHostname = 'auth.oxy.so';
65
- if (authWebUrl) {
66
- try {
67
- idpHostname = new URL(authWebUrl).hostname;
68
- } catch {/* malformed URL, use default */}
69
- }
70
- return hostname === idpHostname;
71
- }
72
-
73
- /**
74
- * Hook for automatic cross-domain web SSO
75
- *
76
- * Uses FedCM (Federated Credential Management) - the modern browser-native
77
- * identity federation API. This is the same technology that powers
78
- * Google's cross-domain SSO (YouTube, Gmail, Maps, etc.).
79
- *
80
- * Key benefits:
81
- * - Works across different TLDs (alia.onl ↔ mention.earth ↔ homiio.com)
82
- * - No third-party cookies required
83
- * - Privacy-preserving (browser mediates identity, IdP can't track)
84
- * - Automatic silent sign-in after initial authentication
85
- *
86
- * For browsers without FedCM (Firefox, older browsers), automatic SSO
87
- * is not possible. Users will see a sign-in button instead.
88
- */
89
- export function useWebSSO({
90
- oxyServices,
91
- onSessionFound,
92
- onSSOUnavailable,
93
- onError,
94
- enabled = true
95
- }) {
96
- const isCheckingRef = useRef(false);
97
- const hasCheckedRef = useRef(false);
98
-
99
- // Check FedCM support once
100
- const fedCMSupported = isWebBrowser() && oxyServices.isFedCMSupported?.();
101
- const authWebUrl = oxyServices.config?.authWebUrl;
102
- const checkSSO = useCallback(async () => {
103
- if (!isWebBrowser() || isCheckingRef.current) {
104
- return null;
105
- }
106
-
107
- // Don't use FedCM on the auth domain itself - it would authenticate against itself
108
- if (isIdentityProvider(authWebUrl)) {
109
- onSSOUnavailable?.();
110
- return null;
111
- }
112
-
113
- // FedCM is the only reliable cross-domain SSO mechanism
114
- if (!fedCMSupported) {
115
- onSSOUnavailable?.();
116
- return null;
117
- }
118
- isCheckingRef.current = true;
119
- try {
120
- const session = await oxyServices.silentSignInWithFedCM?.();
121
- if (session) {
122
- await onSessionFound(session);
123
- return session;
124
- }
125
- onSSOUnavailable?.();
126
- return null;
127
- } catch (error) {
128
- onSSOUnavailable?.();
129
- onError?.(error instanceof Error ? error : new Error(String(error)));
130
- return null;
131
- } finally {
132
- isCheckingRef.current = false;
133
- }
134
- }, [oxyServices, onSessionFound, onSSOUnavailable, onError, fedCMSupported, authWebUrl]);
135
-
136
- /**
137
- * Trigger interactive FedCM sign-in
138
- * This shows the browser's native "Sign in with Oxy" prompt.
139
- * Use this when silent mediation fails (user hasn't previously consented).
140
- */
141
- const signInWithFedCM = useCallback(async () => {
142
- if (!isWebBrowser() || isCheckingRef.current) {
143
- return null;
144
- }
145
- if (!fedCMSupported) {
146
- onError?.(new Error('FedCM is not supported in this browser'));
147
- return null;
148
- }
149
- isCheckingRef.current = true;
150
- try {
151
- const session = await oxyServices.signInWithFedCM?.();
152
- if (session) {
153
- await onSessionFound(session);
154
- return session;
155
- }
156
- return null;
157
- } catch (error) {
158
- onError?.(error instanceof Error ? error : new Error(String(error)));
159
- return null;
160
- } finally {
161
- isCheckingRef.current = false;
162
- }
163
- }, [oxyServices, onSessionFound, onError, fedCMSupported]);
164
-
165
- // Auto-check SSO on mount (web only, FedCM only, not on auth domain).
166
- //
167
- // Run-once is enforced by TWO guards:
168
- // 1. `hasCheckedRef` — cheap per-instance fast-path so effect re-runs
169
- // (from changing deps) within one mount never re-fire.
170
- // 2. `silentSSOAttempted` — module-level, survives remounts/StrictMode so
171
- // silent SSO fires exactly once per page load even if the provider
172
- // unmounts and remounts.
173
- useEffect(() => {
174
- if (!enabled || !isWebBrowser() || hasCheckedRef.current || isIdentityProvider(authWebUrl)) {
175
- if (isIdentityProvider(authWebUrl)) {
176
- onSSOUnavailable?.();
177
- }
178
- return;
179
- }
180
- const signature = ssoSignature(oxyServices);
181
- if (silentSSOAttempted.has(signature)) {
182
- // Already attempted this page load (e.g. before a remount) — do not
183
- // re-fire. Mark the local fast-path too so subsequent re-renders skip.
184
- hasCheckedRef.current = true;
185
- return;
186
- }
187
- hasCheckedRef.current = true;
188
- silentSSOAttempted.add(signature);
189
- if (fedCMSupported) {
190
- checkSSO();
191
- } else {
192
- onSSOUnavailable?.();
193
- }
194
- }, [enabled, checkSSO, fedCMSupported, onSSOUnavailable, oxyServices, authWebUrl]);
195
- return {
196
- checkSSO,
197
- signInWithFedCM,
198
- isChecking: isCheckingRef.current,
199
- isFedCMSupported: fedCMSupported
200
- };
201
- }
202
- export { isWebBrowser };
203
24
  //# sourceMappingURL=useWebSSO.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["useEffect","useRef","useCallback","buildSilentGuardKey","silentSSOAttempted","Set","ssoSignature","oxyServices","getBaseURL","isWebBrowser","window","document","documentElement","isIdentityProvider","authWebUrl","hostname","location","idpHostname","URL","useWebSSO","onSessionFound","onSSOUnavailable","onError","enabled","isCheckingRef","hasCheckedRef","fedCMSupported","isFedCMSupported","config","checkSSO","current","session","silentSignInWithFedCM","error","Error","String","signInWithFedCM","signature","has","add","isChecking"],"sourceRoot":"../../../../src","sources":["ui/hooks/useWebSSO.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["isWebBrowser","window","document","documentElement"],"sourceRoot":"../../../../src","sources":["ui/hooks/useWebSSO.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO,SAASA,YAAYA,CAAA,EAAY;EACtC,OAAO,OAAOC,MAAM,KAAK,WAAW,IAC7B,OAAOC,QAAQ,KAAK,WAAW,IAC/B,OAAOA,QAAQ,CAACC,eAAe,KAAK,WAAW;AACxD","ignoreList":[]}
@@ -15,7 +15,6 @@
15
15
  */
16
16
 
17
17
  /// <reference path="../types/react-native-classname.d.ts" />
18
- /// <reference path="../types/react-native-web-style.d.ts" />
19
18
 
20
19
  // Components
21
20
  export { default as OxyProvider } from "./components/OxyProvider.js";
@@ -1 +1 @@
1
- {"version":3,"names":["default","OxyProvider","OxySignInButton","OxyAuthPrompt","OxyLogo","Avatar","FollowButton","OxyPayButton","FontLoader","setupFonts","OxyIcon","AccountMenu","AccountMenuButton","ProfileButton","ProfileMenu","AccountSwitcher","AccountSwitcherView","useOxy","useAuth","useFollow","useStorage","ProfileScreen","ManageAccountScreen","AccountSwitcherScreen","CreateAccountScreen","AccountMembersScreen","AccountSettingsScreen","useAuthStore","useAccountStore","handleAuthError","isInvalidSessionError","isTimeoutOrNetworkError","extractErrorMessage"],"sourceRoot":"../../../src","sources":["ui/index.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,SAASA,OAAO,IAAIC,WAAW,QAAQ,6BAA0B;AACjE,SAASD,OAAO,IAAIE,eAAe,QAAQ,iCAA8B;AACzE,SAASF,OAAO,IAAIG,aAAa,QAAQ,+BAA4B;AAErE,SAASH,OAAO,IAAII,OAAO,QAAQ,yBAAsB;AACzD,SAASJ,OAAO,IAAIK,MAAM,QAAQ,wBAAqB;AACvD,SAASL,OAAO,IAAIM,YAAY,QAAQ,8BAA2B;AACnE,SAASN,OAAO,IAAIO,YAAY,QAAQ,8BAA2B;AACnE,SAASC,UAAU,EAAEC,UAAU,QAAQ,4BAAyB;AAChE,SAAST,OAAO,IAAIU,OAAO,QAAQ,8BAA2B;AAC9D,SAASV,OAAO,IAAIW,WAAW,QAAQ,6BAA0B;AACjE,SAASX,OAAO,IAAIY,iBAAiB,QAAQ,mCAAgC;AAC7E,SAASZ,OAAO,IAAIa,aAAa,QAAQ,+BAA4B;AACrE,SAASb,OAAO,IAAIc,WAAW,QAAQ,6BAA0B;AACjE,SAASd,OAAO,IAAIe,eAAe,EAAEC,mBAAmB,QAAQ,iCAA8B;;AAE9F;AACA,SAASC,MAAM,QAAQ,yBAAsB;AAC7C,SAASC,OAAO,QAAQ,oBAAiB;AACzC,SAASC,SAAS,QAAQ,sBAAmB;AAC7C,SAASC,UAAU,QAAQ,uBAAoB;AAG/C;AACA,SAASpB,OAAO,IAAIqB,aAAa,QAAQ,4BAAyB;AAClE,SAASrB,OAAO,IAAIsB,mBAAmB,QAAQ,kCAA+B;AAC9E,SAAStB,OAAO,IAAIuB,qBAAqB,QAAQ,oCAAiC;AAClF,SAASvB,OAAO,IAAIwB,mBAAmB,QAAQ,kCAA+B;AAC9E,SAASxB,OAAO,IAAIyB,oBAAoB,QAAQ,mCAAgC;AAChF,SAASzB,OAAO,IAAI0B,qBAAqB,QAAQ,oCAAiC;;AAElF;AACA,SAASC,YAAY,QAAQ,uBAAoB;AACjD,SAASC,eAAe,QAAQ,0BAAuB;;AAEvD;AACA,SACIC,eAAe,EACfC,qBAAqB,EACrBC,uBAAuB,EACvBC,mBAAmB,QAChB,0BAAuB","ignoreList":[]}
1
+ {"version":3,"names":["default","OxyProvider","OxySignInButton","OxyAuthPrompt","OxyLogo","Avatar","FollowButton","OxyPayButton","FontLoader","setupFonts","OxyIcon","AccountMenu","AccountMenuButton","ProfileButton","ProfileMenu","AccountSwitcher","AccountSwitcherView","useOxy","useAuth","useFollow","useStorage","ProfileScreen","ManageAccountScreen","AccountSwitcherScreen","CreateAccountScreen","AccountMembersScreen","AccountSettingsScreen","useAuthStore","useAccountStore","handleAuthError","isInvalidSessionError","isTimeoutOrNetworkError","extractErrorMessage"],"sourceRoot":"../../../src","sources":["ui/index.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,SAASA,OAAO,IAAIC,WAAW,QAAQ,6BAA0B;AACjE,SAASD,OAAO,IAAIE,eAAe,QAAQ,iCAA8B;AACzE,SAASF,OAAO,IAAIG,aAAa,QAAQ,+BAA4B;AAErE,SAASH,OAAO,IAAII,OAAO,QAAQ,yBAAsB;AACzD,SAASJ,OAAO,IAAIK,MAAM,QAAQ,wBAAqB;AACvD,SAASL,OAAO,IAAIM,YAAY,QAAQ,8BAA2B;AACnE,SAASN,OAAO,IAAIO,YAAY,QAAQ,8BAA2B;AACnE,SAASC,UAAU,EAAEC,UAAU,QAAQ,4BAAyB;AAChE,SAAST,OAAO,IAAIU,OAAO,QAAQ,8BAA2B;AAC9D,SAASV,OAAO,IAAIW,WAAW,QAAQ,6BAA0B;AACjE,SAASX,OAAO,IAAIY,iBAAiB,QAAQ,mCAAgC;AAC7E,SAASZ,OAAO,IAAIa,aAAa,QAAQ,+BAA4B;AACrE,SAASb,OAAO,IAAIc,WAAW,QAAQ,6BAA0B;AACjE,SAASd,OAAO,IAAIe,eAAe,EAAEC,mBAAmB,QAAQ,iCAA8B;;AAE9F;AACA,SAASC,MAAM,QAAQ,yBAAsB;AAC7C,SAASC,OAAO,QAAQ,oBAAiB;AACzC,SAASC,SAAS,QAAQ,sBAAmB;AAC7C,SAASC,UAAU,QAAQ,uBAAoB;AAG/C;AACA,SAASpB,OAAO,IAAIqB,aAAa,QAAQ,4BAAyB;AAClE,SAASrB,OAAO,IAAIsB,mBAAmB,QAAQ,kCAA+B;AAC9E,SAAStB,OAAO,IAAIuB,qBAAqB,QAAQ,oCAAiC;AAClF,SAASvB,OAAO,IAAIwB,mBAAmB,QAAQ,kCAA+B;AAC9E,SAASxB,OAAO,IAAIyB,oBAAoB,QAAQ,mCAAgC;AAChF,SAASzB,OAAO,IAAI0B,qBAAqB,QAAQ,oCAAiC;;AAElF;AACA,SAASC,YAAY,QAAQ,uBAAoB;AACjD,SAASC,eAAe,QAAQ,0BAAuB;;AAEvD;AACA,SACIC,eAAe,EACfC,qBAAqB,EACrBC,uBAAuB,EACvBC,mBAAmB,QAChB,0BAAuB","ignoreList":[]}
@@ -38,7 +38,7 @@ const OxyAuthScreen = ({
38
38
  const bloomTheme = useTheme();
39
39
  const {
40
40
  oxyServices,
41
- switchSession,
41
+ handleWebSession,
42
42
  clientId
43
43
  } = useOxy();
44
44
  const {
@@ -50,7 +50,7 @@ const OxyAuthScreen = ({
50
50
  openAuthApproval,
51
51
  openSameDeviceApproval,
52
52
  retry
53
- } = useOxyAuthSession(oxyServices, clientId, switchSession, {
53
+ } = useOxyAuthSession(oxyServices, clientId, handleWebSession, {
54
54
  onSignedIn: onAuthenticated
55
55
  });
56
56
 
@@ -1 +1 @@
1
- {"version":3,"names":["View","Linking","useTheme","Button","Loading","H4","Text","IconCircle","Icons","useOxy","OxyLogo","AnotherDeviceQR","LoadingState","useOxyAuthSession","OXY_ACCOUNTS_WEB_URL","isCrossApexWeb","jsx","_jsx","jsxs","_jsxs","OxyAuthScreen","goBack","onAuthenticated","bloomTheme","oxyServices","switchSession","clientId","qrData","qrPayload","isLoading","error","isWaiting","openAuthApproval","openSameDeviceApproval","retry","onSignedIn","crossApexWeb","className","children","size","color","colors","primary","message","icon","Warning_Stroke2_Corner0_Rounded","variant","fullWidth","onPress","ArrowRotateClockwise_Stroke2_Corner0_Rounded","style","primaryForeground","fillColor","text","openURL","accessibilityLabel"],"sourceRoot":"../../../../src","sources":["ui/screens/OxyAuthScreen.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["View","Linking","useTheme","Button","Loading","H4","Text","IconCircle","Icons","useOxy","OxyLogo","AnotherDeviceQR","LoadingState","useOxyAuthSession","OXY_ACCOUNTS_WEB_URL","isCrossApexWeb","jsx","_jsx","jsxs","_jsxs","OxyAuthScreen","goBack","onAuthenticated","bloomTheme","oxyServices","handleWebSession","clientId","qrData","qrPayload","isLoading","error","isWaiting","openAuthApproval","openSameDeviceApproval","retry","onSignedIn","crossApexWeb","className","children","size","color","colors","primary","message","icon","Warning_Stroke2_Corner0_Rounded","variant","fullWidth","onPress","ArrowRotateClockwise_Stroke2_Corner0_Rounded","style","primaryForeground","fillColor","text","openURL","accessibilityLabel"],"sourceRoot":"../../../../src","sources":["ui/screens/OxyAuthScreen.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ import { SessionClient } from '@oxyhq/core';
4
+ import { createSessionClientHost } from "./sessionClientHost.js";
5
+ import { createTokenTransport } from "./tokenTransport.js";
6
+
7
+ /**
8
+ * Wires a `SessionClient` for `@oxyhq/services`: builds the `SessionClientHost`
9
+ * adapter (Task 1) and the platform `TokenTransport` (Task 3) over the given
10
+ * `OxyServices` instance, and returns both the client and the host — the host
11
+ * is returned (not just the client) so `OxyContext` (Fase 3-B) can call
12
+ * `host.setCurrentAccountId(...)` as the active account changes.
13
+ */
14
+ export function createSessionClient(oxyServices) {
15
+ const host = createSessionClientHost(oxyServices);
16
+ const transport = createTokenTransport(oxyServices);
17
+ const client = new SessionClient(host, {
18
+ transport
19
+ });
20
+ return {
21
+ client,
22
+ host
23
+ };
24
+ }
25
+ //# sourceMappingURL=createSessionClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["SessionClient","createSessionClientHost","createTokenTransport","createSessionClient","oxyServices","host","transport","client"],"sourceRoot":"../../../../src","sources":["ui/session/createSessionClient.ts"],"mappings":";;AACA,SAASA,aAAa,QAAQ,aAAa;AAC3C,SAASC,uBAAuB,QAAQ,wBAAqB;AAC7D,SAASC,oBAAoB,QAAQ,qBAAkB;;AAEvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAACC,WAAwB,EAG1D;EACA,MAAMC,IAAI,GAAGJ,uBAAuB,CAACG,WAAW,CAAC;EACjD,MAAME,SAAS,GAAGJ,oBAAoB,CAACE,WAAW,CAAC;EACnD,MAAMG,MAAM,GAAG,IAAIP,aAAa,CAACK,IAAI,EAAE;IAAEC;EAAU,CAAC,CAAC;EACrD,OAAO;IAAEC,MAAM;IAAEF;EAAK,CAAC;AACzB","ignoreList":[]}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Session-sync integration layer (Fase 3-A) — intra-package use only.
5
+ *
6
+ * These modules let `@oxyhq/services` drive the platform-agnostic
7
+ * `SessionClient` (in `@oxyhq/core`): a thin host adapter over `OxyServices`,
8
+ * pure `DeviceSessionState → services` projection helpers, a platform token
9
+ * transport, and the factory that wires them together. Nothing here is
10
+ * re-exported from the package root — `OxyContext` consumes it directly in
11
+ * Fase 3-B.
12
+ */
13
+ export { createSessionClient } from "./createSessionClient.js";
14
+ export { createSessionClientHost } from "./sessionClientHost.js";
15
+ export { createTokenTransport } from "./tokenTransport.js";
16
+ export { accountIdsOf, activeSessionIdOf, activeUserOf, deviceStateToClientSessions } from "./projectSessionState.js";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createSessionClient","createSessionClientHost","createTokenTransport","accountIdsOf","activeSessionIdOf","activeUserOf","deviceStateToClientSessions"],"sourceRoot":"../../../../src","sources":["ui/session/index.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,mBAAmB,QAAQ,0BAAuB;AAC3D,SAASC,uBAAuB,QAAQ,wBAAqB;AAC7D,SAASC,oBAAoB,QAAQ,qBAAkB;AACvD,SACEC,YAAY,EACZC,iBAAiB,EACjBC,YAAY,EACZC,2BAA2B,QACtB,0BAAuB","ignoreList":[]}