@oxy.so/core 1.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 (673) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +16 -0
  3. package/README.md +221 -0
  4. package/dist/cjs/.tsbuildinfo +1 -0
  5. package/dist/cjs/HttpService.js +1270 -0
  6. package/dist/cjs/OxyServices.base.js +390 -0
  7. package/dist/cjs/OxyServices.errors.js +95 -0
  8. package/dist/cjs/OxyServices.js +72 -0
  9. package/dist/cjs/boot/sessionColdBoot.js +395 -0
  10. package/dist/cjs/constants/version.js +16 -0
  11. package/dist/cjs/crypto/aead.js +79 -0
  12. package/dist/cjs/crypto/ecdh.js +35 -0
  13. package/dist/cjs/crypto/identityMarker.js +255 -0
  14. package/dist/cjs/crypto/kdf.js +39 -0
  15. package/dist/cjs/crypto/keyManager.js +2234 -0
  16. package/dist/cjs/crypto/polyfill.js +131 -0
  17. package/dist/cjs/crypto/recoveryPhrase.js +242 -0
  18. package/dist/cjs/crypto/signatureService.js +273 -0
  19. package/dist/cjs/i18n/accountCategoryLabels.js +44 -0
  20. package/dist/cjs/i18n/accountRoleLabels.js +27 -0
  21. package/dist/cjs/i18n/index.js +90 -0
  22. package/dist/cjs/i18n/locales/ar-SA.json +282 -0
  23. package/dist/cjs/i18n/locales/ca-ES.json +282 -0
  24. package/dist/cjs/i18n/locales/de-DE.json +282 -0
  25. package/dist/cjs/i18n/locales/en-US.json +2161 -0
  26. package/dist/cjs/i18n/locales/es-ES.json +2161 -0
  27. package/dist/cjs/i18n/locales/fr-FR.json +282 -0
  28. package/dist/cjs/i18n/locales/it-IT.json +282 -0
  29. package/dist/cjs/i18n/locales/ja-JP.json +282 -0
  30. package/dist/cjs/i18n/locales/ko-KR.json +282 -0
  31. package/dist/cjs/i18n/locales/locales/ar-SA.json +282 -0
  32. package/dist/cjs/i18n/locales/locales/ca-ES.json +282 -0
  33. package/dist/cjs/i18n/locales/locales/de-DE.json +282 -0
  34. package/dist/cjs/i18n/locales/locales/en-US.json +2161 -0
  35. package/dist/cjs/i18n/locales/locales/es-ES.json +2161 -0
  36. package/dist/cjs/i18n/locales/locales/fr-FR.json +282 -0
  37. package/dist/cjs/i18n/locales/locales/it-IT.json +282 -0
  38. package/dist/cjs/i18n/locales/locales/ja-JP.json +282 -0
  39. package/dist/cjs/i18n/locales/locales/ko-KR.json +282 -0
  40. package/dist/cjs/i18n/locales/locales/pt-PT.json +282 -0
  41. package/dist/cjs/i18n/locales/locales/zh-CN.json +282 -0
  42. package/dist/cjs/i18n/locales/pt-PT.json +282 -0
  43. package/dist/cjs/i18n/locales/zh-CN.json +282 -0
  44. package/dist/cjs/i18n/reputationCategoryLabels.js +20 -0
  45. package/dist/cjs/i18n/trustTierLabels.js +19 -0
  46. package/dist/cjs/index.js +498 -0
  47. package/dist/cjs/inference/OxyInferenceClient.js +544 -0
  48. package/dist/cjs/logger/index.js +149 -0
  49. package/dist/cjs/mixins/OxyServices.accounts.js +555 -0
  50. package/dist/cjs/mixins/OxyServices.analytics.js +49 -0
  51. package/dist/cjs/mixins/OxyServices.appData.js +108 -0
  52. package/dist/cjs/mixins/OxyServices.assets.js +764 -0
  53. package/dist/cjs/mixins/OxyServices.auth.js +1254 -0
  54. package/dist/cjs/mixins/OxyServices.chains.js +73 -0
  55. package/dist/cjs/mixins/OxyServices.civic.js +611 -0
  56. package/dist/cjs/mixins/OxyServices.connectedApps.js +78 -0
  57. package/dist/cjs/mixins/OxyServices.contacts.js +50 -0
  58. package/dist/cjs/mixins/OxyServices.deviceBoot.js +191 -0
  59. package/dist/cjs/mixins/OxyServices.deviceTransfer.js +314 -0
  60. package/dist/cjs/mixins/OxyServices.devices.js +116 -0
  61. package/dist/cjs/mixins/OxyServices.features.js +335 -0
  62. package/dist/cjs/mixins/OxyServices.followGraph.js +221 -0
  63. package/dist/cjs/mixins/OxyServices.identity.js +461 -0
  64. package/dist/cjs/mixins/OxyServices.identityBackup.js +172 -0
  65. package/dist/cjs/mixins/OxyServices.inference.js +59 -0
  66. package/dist/cjs/mixins/OxyServices.language.js +125 -0
  67. package/dist/cjs/mixins/OxyServices.links.js +72 -0
  68. package/dist/cjs/mixins/OxyServices.location.js +43 -0
  69. package/dist/cjs/mixins/OxyServices.nodes.js +175 -0
  70. package/dist/cjs/mixins/OxyServices.notifications.js +63 -0
  71. package/dist/cjs/mixins/OxyServices.payment.js +158 -0
  72. package/dist/cjs/mixins/OxyServices.privacy.js +199 -0
  73. package/dist/cjs/mixins/OxyServices.reputation.js +289 -0
  74. package/dist/cjs/mixins/OxyServices.security.js +89 -0
  75. package/dist/cjs/mixins/OxyServices.store.js +266 -0
  76. package/dist/cjs/mixins/OxyServices.topics.js +137 -0
  77. package/dist/cjs/mixins/OxyServices.user.js +902 -0
  78. package/dist/cjs/mixins/OxyServices.utility.js +1098 -0
  79. package/dist/cjs/mixins/index.js +135 -0
  80. package/dist/cjs/mixins/mixinHelpers.js +53 -0
  81. package/dist/cjs/models/Topic.js +16 -0
  82. package/dist/cjs/models/interfaces.js +20 -0
  83. package/dist/cjs/models/session.js +2 -0
  84. package/dist/cjs/server/auth.js +167 -0
  85. package/dist/cjs/server/capabilityTicket.js +192 -0
  86. package/dist/cjs/server/cors.js +225 -0
  87. package/dist/cjs/server/index.js +97 -0
  88. package/dist/cjs/server/rateLimit.js +207 -0
  89. package/dist/cjs/server/safeFetch.js +458 -0
  90. package/dist/cjs/server/securityHeaders.js +377 -0
  91. package/dist/cjs/server/userInvalidation.js +156 -0
  92. package/dist/cjs/server/verifySecret.js +50 -0
  93. package/dist/cjs/session/SessionClient.js +865 -0
  94. package/dist/cjs/session/accountDelegationAccess.js +48 -0
  95. package/dist/cjs/session/accountDialogController.js +1131 -0
  96. package/dist/cjs/session/accountSwitchTargets.js +81 -0
  97. package/dist/cjs/session/authStateStore.js +404 -0
  98. package/dist/cjs/session/createSessionClient.js +32 -0
  99. package/dist/cjs/session/deviceDirectory.js +143 -0
  100. package/dist/cjs/session/deviceSwitcherRows.js +76 -0
  101. package/dist/cjs/session/identityPin.js +256 -0
  102. package/dist/cjs/session/identitySession.js +135 -0
  103. package/dist/cjs/session/projectSessionState.js +121 -0
  104. package/dist/cjs/session/refresh.js +398 -0
  105. package/dist/cjs/session/sessionClientHost.js +34 -0
  106. package/dist/cjs/session/sharedDeviceCredential.js +247 -0
  107. package/dist/cjs/session/socketLoader.js +55 -0
  108. package/dist/cjs/shared/utils/colorUtils.js +153 -0
  109. package/dist/cjs/shared/utils/errorUtils.js +183 -0
  110. package/dist/cjs/shared/utils/index.js +49 -0
  111. package/dist/cjs/shared/utils/networkUtils.js +183 -0
  112. package/dist/cjs/shared/utils/themeUtils.js +106 -0
  113. package/dist/cjs/utils/accountCacheSweep.js +80 -0
  114. package/dist/cjs/utils/accountUtils.js +140 -0
  115. package/dist/cjs/utils/activityId.js +6 -0
  116. package/dist/cjs/utils/apiUtils.js +91 -0
  117. package/dist/cjs/utils/asyncUtils.js +222 -0
  118. package/dist/cjs/utils/authHelpers.js +120 -0
  119. package/dist/cjs/utils/authWebUrl.js +19 -0
  120. package/dist/cjs/utils/avatarUtils.js +29 -0
  121. package/dist/cjs/utils/cache.js +235 -0
  122. package/dist/cjs/utils/cacheKey.js +85 -0
  123. package/dist/cjs/utils/coldBoot.js +122 -0
  124. package/dist/cjs/utils/commonsApproval.js +31 -0
  125. package/dist/cjs/utils/commonsDelivery.js +59 -0
  126. package/dist/cjs/utils/deviceManager.js +174 -0
  127. package/dist/cjs/utils/displayNamePolicyRanges.generated.js +60 -0
  128. package/dist/cjs/utils/edgeRegion.js +6 -0
  129. package/dist/cjs/utils/errorUtils.js +243 -0
  130. package/dist/cjs/utils/identityCacheSweep.js +97 -0
  131. package/dist/cjs/utils/languageUtils.js +224 -0
  132. package/dist/cjs/utils/oauthPkce.js +311 -0
  133. package/dist/cjs/utils/officialOrigins.js +64 -0
  134. package/dist/cjs/utils/oxyServiceEnvironment.js +19 -0
  135. package/dist/cjs/utils/platform.js +119 -0
  136. package/dist/cjs/utils/profileLinks.js +63 -0
  137. package/dist/cjs/utils/redactUrl.js +29 -0
  138. package/dist/cjs/utils/registrableApex.js +45 -0
  139. package/dist/cjs/utils/requestUtils.js +209 -0
  140. package/dist/cjs/utils/sessionUtils.js +181 -0
  141. package/dist/cjs/utils/textNormalization.js +158 -0
  142. package/dist/cjs/utils/userHandle.js +37 -0
  143. package/dist/cjs/utils/userIdentity.js +50 -0
  144. package/dist/cjs/utils/validationUtils.js +370 -0
  145. package/dist/cjs/utils/webauthnOrigin.js +51 -0
  146. package/dist/esm/.tsbuildinfo +1 -0
  147. package/dist/esm/HttpService.js +1266 -0
  148. package/dist/esm/OxyServices.base.js +386 -0
  149. package/dist/esm/OxyServices.errors.js +88 -0
  150. package/dist/esm/OxyServices.js +66 -0
  151. package/dist/esm/boot/sessionColdBoot.js +392 -0
  152. package/dist/esm/constants/version.js +13 -0
  153. package/dist/esm/crypto/aead.js +74 -0
  154. package/dist/esm/crypto/ecdh.js +32 -0
  155. package/dist/esm/crypto/identityMarker.js +248 -0
  156. package/dist/esm/crypto/kdf.js +36 -0
  157. package/dist/esm/crypto/keyManager.js +2227 -0
  158. package/dist/esm/crypto/polyfill.js +129 -0
  159. package/dist/esm/crypto/recoveryPhrase.js +238 -0
  160. package/dist/esm/crypto/signatureService.js +269 -0
  161. package/dist/esm/i18n/accountCategoryLabels.js +37 -0
  162. package/dist/esm/i18n/accountRoleLabels.js +20 -0
  163. package/dist/esm/i18n/index.js +83 -0
  164. package/dist/esm/i18n/locales/ar-SA.json +282 -0
  165. package/dist/esm/i18n/locales/ca-ES.json +282 -0
  166. package/dist/esm/i18n/locales/de-DE.json +282 -0
  167. package/dist/esm/i18n/locales/en-US.json +2161 -0
  168. package/dist/esm/i18n/locales/es-ES.json +2161 -0
  169. package/dist/esm/i18n/locales/fr-FR.json +282 -0
  170. package/dist/esm/i18n/locales/it-IT.json +282 -0
  171. package/dist/esm/i18n/locales/ja-JP.json +282 -0
  172. package/dist/esm/i18n/locales/ko-KR.json +282 -0
  173. package/dist/esm/i18n/locales/locales/ar-SA.json +282 -0
  174. package/dist/esm/i18n/locales/locales/ca-ES.json +282 -0
  175. package/dist/esm/i18n/locales/locales/de-DE.json +282 -0
  176. package/dist/esm/i18n/locales/locales/en-US.json +2161 -0
  177. package/dist/esm/i18n/locales/locales/es-ES.json +2161 -0
  178. package/dist/esm/i18n/locales/locales/fr-FR.json +282 -0
  179. package/dist/esm/i18n/locales/locales/it-IT.json +282 -0
  180. package/dist/esm/i18n/locales/locales/ja-JP.json +282 -0
  181. package/dist/esm/i18n/locales/locales/ko-KR.json +282 -0
  182. package/dist/esm/i18n/locales/locales/pt-PT.json +282 -0
  183. package/dist/esm/i18n/locales/locales/zh-CN.json +282 -0
  184. package/dist/esm/i18n/locales/pt-PT.json +282 -0
  185. package/dist/esm/i18n/locales/zh-CN.json +282 -0
  186. package/dist/esm/i18n/reputationCategoryLabels.js +13 -0
  187. package/dist/esm/i18n/trustTierLabels.js +12 -0
  188. package/dist/esm/index.js +254 -0
  189. package/dist/esm/inference/OxyInferenceClient.js +538 -0
  190. package/dist/esm/logger/index.js +140 -0
  191. package/dist/esm/mixins/OxyServices.accounts.js +543 -0
  192. package/dist/esm/mixins/OxyServices.analytics.js +46 -0
  193. package/dist/esm/mixins/OxyServices.appData.js +103 -0
  194. package/dist/esm/mixins/OxyServices.assets.js +761 -0
  195. package/dist/esm/mixins/OxyServices.auth.js +1247 -0
  196. package/dist/esm/mixins/OxyServices.chains.js +70 -0
  197. package/dist/esm/mixins/OxyServices.civic.js +605 -0
  198. package/dist/esm/mixins/OxyServices.connectedApps.js +75 -0
  199. package/dist/esm/mixins/OxyServices.contacts.js +47 -0
  200. package/dist/esm/mixins/OxyServices.deviceBoot.js +186 -0
  201. package/dist/esm/mixins/OxyServices.deviceTransfer.js +311 -0
  202. package/dist/esm/mixins/OxyServices.devices.js +113 -0
  203. package/dist/esm/mixins/OxyServices.features.js +332 -0
  204. package/dist/esm/mixins/OxyServices.followGraph.js +218 -0
  205. package/dist/esm/mixins/OxyServices.identity.js +457 -0
  206. package/dist/esm/mixins/OxyServices.identityBackup.js +169 -0
  207. package/dist/esm/mixins/OxyServices.inference.js +56 -0
  208. package/dist/esm/mixins/OxyServices.language.js +122 -0
  209. package/dist/esm/mixins/OxyServices.links.js +69 -0
  210. package/dist/esm/mixins/OxyServices.location.js +40 -0
  211. package/dist/esm/mixins/OxyServices.nodes.js +172 -0
  212. package/dist/esm/mixins/OxyServices.notifications.js +60 -0
  213. package/dist/esm/mixins/OxyServices.payment.js +155 -0
  214. package/dist/esm/mixins/OxyServices.privacy.js +196 -0
  215. package/dist/esm/mixins/OxyServices.reputation.js +286 -0
  216. package/dist/esm/mixins/OxyServices.security.js +86 -0
  217. package/dist/esm/mixins/OxyServices.store.js +263 -0
  218. package/dist/esm/mixins/OxyServices.topics.js +134 -0
  219. package/dist/esm/mixins/OxyServices.user.js +899 -0
  220. package/dist/esm/mixins/OxyServices.utility.js +1095 -0
  221. package/dist/esm/mixins/index.js +132 -0
  222. package/dist/esm/mixins/mixinHelpers.js +48 -0
  223. package/dist/esm/models/Topic.js +13 -0
  224. package/dist/esm/models/interfaces.js +17 -0
  225. package/dist/esm/models/session.js +1 -0
  226. package/dist/esm/server/auth.js +154 -0
  227. package/dist/esm/server/capabilityTicket.js +183 -0
  228. package/dist/esm/server/cors.js +220 -0
  229. package/dist/esm/server/index.js +47 -0
  230. package/dist/esm/server/rateLimit.js +201 -0
  231. package/dist/esm/server/safeFetch.js +447 -0
  232. package/dist/esm/server/securityHeaders.js +364 -0
  233. package/dist/esm/server/userInvalidation.js +152 -0
  234. package/dist/esm/server/verifySecret.js +47 -0
  235. package/dist/esm/session/SessionClient.js +861 -0
  236. package/dist/esm/session/accountDelegationAccess.js +45 -0
  237. package/dist/esm/session/accountDialogController.js +1126 -0
  238. package/dist/esm/session/accountSwitchTargets.js +77 -0
  239. package/dist/esm/session/authStateStore.js +398 -0
  240. package/dist/esm/session/createSessionClient.js +29 -0
  241. package/dist/esm/session/deviceDirectory.js +135 -0
  242. package/dist/esm/session/deviceSwitcherRows.js +72 -0
  243. package/dist/esm/session/identityPin.js +249 -0
  244. package/dist/esm/session/identitySession.js +131 -0
  245. package/dist/esm/session/projectSessionState.js +114 -0
  246. package/dist/esm/session/refresh.js +390 -0
  247. package/dist/esm/session/sessionClientHost.js +31 -0
  248. package/dist/esm/session/sharedDeviceCredential.js +239 -0
  249. package/dist/esm/session/socketLoader.js +19 -0
  250. package/dist/esm/shared/utils/colorUtils.js +143 -0
  251. package/dist/esm/shared/utils/errorUtils.js +170 -0
  252. package/dist/esm/shared/utils/index.js +15 -0
  253. package/dist/esm/shared/utils/networkUtils.js +173 -0
  254. package/dist/esm/shared/utils/themeUtils.js +98 -0
  255. package/dist/esm/utils/accountCacheSweep.js +75 -0
  256. package/dist/esm/utils/accountUtils.js +131 -0
  257. package/dist/esm/utils/activityId.js +2 -0
  258. package/dist/esm/utils/apiUtils.js +84 -0
  259. package/dist/esm/utils/asyncUtils.js +207 -0
  260. package/dist/esm/utils/authHelpers.js +111 -0
  261. package/dist/esm/utils/authWebUrl.js +16 -0
  262. package/dist/esm/utils/avatarUtils.js +26 -0
  263. package/dist/esm/utils/cache.js +227 -0
  264. package/dist/esm/utils/cacheKey.js +80 -0
  265. package/dist/esm/utils/coldBoot.js +119 -0
  266. package/dist/esm/utils/commonsApproval.js +27 -0
  267. package/dist/esm/utils/commonsDelivery.js +54 -0
  268. package/dist/esm/utils/deviceManager.js +170 -0
  269. package/dist/esm/utils/displayNamePolicyRanges.generated.js +57 -0
  270. package/dist/esm/utils/edgeRegion.js +2 -0
  271. package/dist/esm/utils/errorUtils.js +232 -0
  272. package/dist/esm/utils/identityCacheSweep.js +92 -0
  273. package/dist/esm/utils/languageUtils.js +212 -0
  274. package/dist/esm/utils/oauthPkce.js +297 -0
  275. package/dist/esm/utils/officialOrigins.js +59 -0
  276. package/dist/esm/utils/oxyServiceEnvironment.js +16 -0
  277. package/dist/esm/utils/platform.js +110 -0
  278. package/dist/esm/utils/profileLinks.js +60 -0
  279. package/dist/esm/utils/redactUrl.js +26 -0
  280. package/dist/esm/utils/registrableApex.js +42 -0
  281. package/dist/esm/utils/requestUtils.js +203 -0
  282. package/dist/esm/utils/sessionUtils.js +171 -0
  283. package/dist/esm/utils/textNormalization.js +154 -0
  284. package/dist/esm/utils/userHandle.js +33 -0
  285. package/dist/esm/utils/userIdentity.js +45 -0
  286. package/dist/esm/utils/validationUtils.js +350 -0
  287. package/dist/esm/utils/webauthnOrigin.js +48 -0
  288. package/dist/types/.tsbuildinfo +1 -0
  289. package/dist/types/HttpService.d.ts +413 -0
  290. package/dist/types/OxyServices.base.d.ts +187 -0
  291. package/dist/types/OxyServices.d.ts +139 -0
  292. package/dist/types/OxyServices.errors.d.ts +84 -0
  293. package/dist/types/boot/sessionColdBoot.d.ts +140 -0
  294. package/dist/types/constants/version.d.ts +13 -0
  295. package/dist/types/crypto/aead.d.ts +56 -0
  296. package/dist/types/crypto/ecdh.d.ts +29 -0
  297. package/dist/types/crypto/identityMarker.d.ts +94 -0
  298. package/dist/types/crypto/kdf.d.ts +25 -0
  299. package/dist/types/crypto/keyManager.d.ts +582 -0
  300. package/dist/types/crypto/polyfill.d.ts +25 -0
  301. package/dist/types/crypto/recoveryPhrase.d.ts +173 -0
  302. package/dist/types/crypto/signatureService.d.ts +136 -0
  303. package/dist/types/i18n/accountCategoryLabels.d.ts +34 -0
  304. package/dist/types/i18n/accountRoleLabels.d.ts +10 -0
  305. package/dist/types/i18n/index.d.ts +3 -0
  306. package/dist/types/i18n/reputationCategoryLabels.d.ts +10 -0
  307. package/dist/types/i18n/trustTierLabels.d.ts +9 -0
  308. package/dist/types/index.d.ts +145 -0
  309. package/dist/types/inference/OxyInferenceClient.d.ts +342 -0
  310. package/dist/types/logger/index.d.ts +104 -0
  311. package/dist/types/mixins/OxyServices.accounts.d.ts +868 -0
  312. package/dist/types/mixins/OxyServices.analytics.d.ts +72 -0
  313. package/dist/types/mixins/OxyServices.appData.d.ts +108 -0
  314. package/dist/types/mixins/OxyServices.assets.d.ts +329 -0
  315. package/dist/types/mixins/OxyServices.auth.d.ts +908 -0
  316. package/dist/types/mixins/OxyServices.chains.d.ts +156 -0
  317. package/dist/types/mixins/OxyServices.civic.d.ts +510 -0
  318. package/dist/types/mixins/OxyServices.connectedApps.d.ts +169 -0
  319. package/dist/types/mixins/OxyServices.contacts.d.ts +100 -0
  320. package/dist/types/mixins/OxyServices.deviceBoot.d.ts +185 -0
  321. package/dist/types/mixins/OxyServices.deviceTransfer.d.ts +149 -0
  322. package/dist/types/mixins/OxyServices.devices.d.ts +103 -0
  323. package/dist/types/mixins/OxyServices.features.d.ts +250 -0
  324. package/dist/types/mixins/OxyServices.followGraph.d.ts +223 -0
  325. package/dist/types/mixins/OxyServices.identity.d.ts +351 -0
  326. package/dist/types/mixins/OxyServices.identityBackup.d.ts +129 -0
  327. package/dist/types/mixins/OxyServices.inference.d.ts +95 -0
  328. package/dist/types/mixins/OxyServices.language.d.ts +87 -0
  329. package/dist/types/mixins/OxyServices.links.d.ts +104 -0
  330. package/dist/types/mixins/OxyServices.location.d.ts +70 -0
  331. package/dist/types/mixins/OxyServices.nodes.d.ts +198 -0
  332. package/dist/types/mixins/OxyServices.notifications.d.ts +143 -0
  333. package/dist/types/mixins/OxyServices.payment.d.ts +117 -0
  334. package/dist/types/mixins/OxyServices.privacy.d.ts +146 -0
  335. package/dist/types/mixins/OxyServices.reputation.d.ts +202 -0
  336. package/dist/types/mixins/OxyServices.security.d.ts +84 -0
  337. package/dist/types/mixins/OxyServices.store.d.ts +334 -0
  338. package/dist/types/mixins/OxyServices.topics.d.ts +110 -0
  339. package/dist/types/mixins/OxyServices.user.d.ts +558 -0
  340. package/dist/types/mixins/OxyServices.utility.d.ts +393 -0
  341. package/dist/types/mixins/index.d.ts +87 -0
  342. package/dist/types/mixins/mixinHelpers.d.ts +31 -0
  343. package/dist/types/models/Topic.d.ts +42 -0
  344. package/dist/types/models/interfaces.d.ts +675 -0
  345. package/dist/types/models/session.d.ts +51 -0
  346. package/dist/types/server/auth.d.ts +130 -0
  347. package/dist/types/server/capabilityTicket.d.ts +41 -0
  348. package/dist/types/server/cors.d.ts +98 -0
  349. package/dist/types/server/index.d.ts +35 -0
  350. package/dist/types/server/rateLimit.d.ts +40 -0
  351. package/dist/types/server/safeFetch.d.ts +137 -0
  352. package/dist/types/server/securityHeaders.d.ts +221 -0
  353. package/dist/types/server/userInvalidation.d.ts +114 -0
  354. package/dist/types/server/verifySecret.d.ts +29 -0
  355. package/dist/types/session/SessionClient.d.ts +418 -0
  356. package/dist/types/session/accountDelegationAccess.d.ts +40 -0
  357. package/dist/types/session/accountDialogController.d.ts +648 -0
  358. package/dist/types/session/accountSwitchTargets.d.ts +70 -0
  359. package/dist/types/session/authStateStore.d.ts +153 -0
  360. package/dist/types/session/createSessionClient.d.ts +30 -0
  361. package/dist/types/session/deviceDirectory.d.ts +182 -0
  362. package/dist/types/session/deviceSwitcherRows.d.ts +92 -0
  363. package/dist/types/session/identityPin.d.ts +87 -0
  364. package/dist/types/session/identitySession.d.ts +105 -0
  365. package/dist/types/session/projectSessionState.d.ts +74 -0
  366. package/dist/types/session/refresh.d.ts +179 -0
  367. package/dist/types/session/sessionClientHost.d.ts +18 -0
  368. package/dist/types/session/sharedDeviceCredential.d.ts +202 -0
  369. package/dist/types/session/socketLoader.d.ts +11 -0
  370. package/dist/types/shared/utils/colorUtils.d.ts +104 -0
  371. package/dist/types/shared/utils/errorUtils.d.ts +97 -0
  372. package/dist/types/shared/utils/index.d.ts +13 -0
  373. package/dist/types/shared/utils/networkUtils.d.ts +139 -0
  374. package/dist/types/shared/utils/themeUtils.d.ts +90 -0
  375. package/dist/types/utils/accountCacheSweep.d.ts +75 -0
  376. package/dist/types/utils/accountUtils.d.ts +100 -0
  377. package/dist/types/utils/activityId.d.ts +2 -0
  378. package/dist/types/utils/apiUtils.d.ts +95 -0
  379. package/dist/types/utils/asyncUtils.d.ts +62 -0
  380. package/dist/types/utils/authHelpers.d.ts +58 -0
  381. package/dist/types/utils/authWebUrl.d.ts +16 -0
  382. package/dist/types/utils/avatarUtils.d.ts +16 -0
  383. package/dist/types/utils/cache.d.ts +130 -0
  384. package/dist/types/utils/cacheKey.d.ts +66 -0
  385. package/dist/types/utils/coldBoot.d.ts +131 -0
  386. package/dist/types/utils/commonsApproval.d.ts +13 -0
  387. package/dist/types/utils/commonsDelivery.d.ts +105 -0
  388. package/dist/types/utils/deviceManager.d.ts +65 -0
  389. package/dist/types/utils/displayNamePolicyRanges.generated.d.ts +57 -0
  390. package/dist/types/utils/edgeRegion.d.ts +2 -0
  391. package/dist/types/utils/errorUtils.d.ts +125 -0
  392. package/dist/types/utils/identityCacheSweep.d.ts +80 -0
  393. package/dist/types/utils/languageUtils.d.ts +100 -0
  394. package/dist/types/utils/oauthPkce.d.ts +157 -0
  395. package/dist/types/utils/officialOrigins.d.ts +13 -0
  396. package/dist/types/utils/oxyServiceEnvironment.d.ts +17 -0
  397. package/dist/types/utils/platform.d.ts +49 -0
  398. package/dist/types/utils/profileLinks.d.ts +44 -0
  399. package/dist/types/utils/redactUrl.d.ts +17 -0
  400. package/dist/types/utils/registrableApex.d.ts +27 -0
  401. package/dist/types/utils/requestUtils.d.ts +123 -0
  402. package/dist/types/utils/sessionUtils.d.ts +54 -0
  403. package/dist/types/utils/textNormalization.d.ts +103 -0
  404. package/dist/types/utils/userHandle.d.ts +26 -0
  405. package/dist/types/utils/userIdentity.d.ts +21 -0
  406. package/dist/types/utils/validationUtils.d.ts +268 -0
  407. package/dist/types/utils/webauthnOrigin.d.ts +32 -0
  408. package/package.json +168 -0
  409. package/src/HttpService.ts +1553 -0
  410. package/src/OxyServices.base.ts +478 -0
  411. package/src/OxyServices.errors.ts +122 -0
  412. package/src/OxyServices.ts +172 -0
  413. package/src/__tests__/authSocket.test.ts +96 -0
  414. package/src/__tests__/httpServiceActivityId.test.ts +49 -0
  415. package/src/__tests__/httpServiceAuthSelfAwait.test.ts +108 -0
  416. package/src/__tests__/httpServiceCache.test.ts +318 -0
  417. package/src/__tests__/httpServiceCsrf.test.ts +235 -0
  418. package/src/__tests__/httpServiceFormEncoded.test.ts +142 -0
  419. package/src/__tests__/httpServiceQueueDeadlock.test.ts +128 -0
  420. package/src/__tests__/httpServiceUnwrapEnvelope.test.ts +115 -0
  421. package/src/__tests__/inSessionRefresh.test.ts +260 -0
  422. package/src/__tests__/linkedClient.test.ts +370 -0
  423. package/src/__tests__/parseHttpErrorBody.test.ts +116 -0
  424. package/src/__tests__/serverValueImportsDeclared.test.ts +120 -0
  425. package/src/__tests__/userIdentity.test.ts +143 -0
  426. package/src/boot/__tests__/sessionColdBoot.identity.test.ts +393 -0
  427. package/src/boot/__tests__/sessionColdBoot.sharedDevice.test.ts +325 -0
  428. package/src/boot/__tests__/sessionColdBoot.test.ts +570 -0
  429. package/src/boot/sessionColdBoot.ts +529 -0
  430. package/src/constants/version.ts +15 -0
  431. package/src/crypto/__tests__/backupMaterial.test.ts +86 -0
  432. package/src/crypto/__tests__/cryptoPrimitives.test.ts +226 -0
  433. package/src/crypto/__tests__/identityMocks.ts +125 -0
  434. package/src/crypto/__tests__/keyManager.atomicity.test.ts +272 -0
  435. package/src/crypto/__tests__/keyManager.cacheSafety.test.ts +175 -0
  436. package/src/crypto/__tests__/keyManager.identityStatus.test.ts +217 -0
  437. package/src/crypto/__tests__/keyManager.recoveryLadder.test.ts +179 -0
  438. package/src/crypto/__tests__/keyManager.recoveryMnemonic.test.ts +138 -0
  439. package/src/crypto/__tests__/keyManager.storageMigration.test.ts +227 -0
  440. package/src/crypto/__tests__/keyManager.test.ts +329 -0
  441. package/src/crypto/__tests__/polyfill.test.ts +109 -0
  442. package/src/crypto/__tests__/recoveryPhrase.test.ts +61 -0
  443. package/src/crypto/__tests__/scopedSeed.test.ts +126 -0
  444. package/src/crypto/__tests__/signChallengeShared.test.ts +63 -0
  445. package/src/crypto/__tests__/signedRecord.test.ts +230 -0
  446. package/src/crypto/aead.ts +97 -0
  447. package/src/crypto/ecdh.ts +37 -0
  448. package/src/crypto/identityMarker.ts +291 -0
  449. package/src/crypto/kdf.ts +43 -0
  450. package/src/crypto/keyManager.ts +2607 -0
  451. package/src/crypto/polyfill.ts +143 -0
  452. package/src/crypto/recoveryPhrase.ts +337 -0
  453. package/src/crypto/signatureService.ts +350 -0
  454. package/src/i18n/__tests__/accountCategoryLabels.test.ts +62 -0
  455. package/src/i18n/__tests__/accountRoleLabels.test.ts +54 -0
  456. package/src/i18n/__tests__/reputationCategoryLabels.test.ts +56 -0
  457. package/src/i18n/__tests__/trustTierLabels.test.ts +47 -0
  458. package/src/i18n/accountCategoryLabels.ts +44 -0
  459. package/src/i18n/accountRoleLabels.ts +26 -0
  460. package/src/i18n/index.ts +88 -0
  461. package/src/i18n/locales/ar-SA.json +282 -0
  462. package/src/i18n/locales/ca-ES.json +282 -0
  463. package/src/i18n/locales/de-DE.json +282 -0
  464. package/src/i18n/locales/en-US.json +2161 -0
  465. package/src/i18n/locales/es-ES.json +2161 -0
  466. package/src/i18n/locales/fr-FR.json +282 -0
  467. package/src/i18n/locales/it-IT.json +282 -0
  468. package/src/i18n/locales/ja-JP.json +282 -0
  469. package/src/i18n/locales/ko-KR.json +282 -0
  470. package/src/i18n/locales/pt-PT.json +282 -0
  471. package/src/i18n/locales/zh-CN.json +282 -0
  472. package/src/i18n/reputationCategoryLabels.ts +20 -0
  473. package/src/i18n/trustTierLabels.ts +18 -0
  474. package/src/index.ts +881 -0
  475. package/src/inference/OxyInferenceClient.ts +888 -0
  476. package/src/inference/__tests__/OxyInferenceClient.test.ts +834 -0
  477. package/src/logger/__tests__/logger.test.ts +207 -0
  478. package/src/logger/index.ts +217 -0
  479. package/src/mixins/OxyServices.accounts.ts +1330 -0
  480. package/src/mixins/OxyServices.analytics.ts +53 -0
  481. package/src/mixins/OxyServices.appData.ts +158 -0
  482. package/src/mixins/OxyServices.assets.ts +861 -0
  483. package/src/mixins/OxyServices.auth.ts +1858 -0
  484. package/src/mixins/OxyServices.chains.ts +134 -0
  485. package/src/mixins/OxyServices.civic.ts +945 -0
  486. package/src/mixins/OxyServices.connectedApps.ts +174 -0
  487. package/src/mixins/OxyServices.contacts.ts +73 -0
  488. package/src/mixins/OxyServices.deviceBoot.ts +210 -0
  489. package/src/mixins/OxyServices.deviceTransfer.ts +393 -0
  490. package/src/mixins/OxyServices.devices.ts +120 -0
  491. package/src/mixins/OxyServices.features.ts +454 -0
  492. package/src/mixins/OxyServices.followGraph.ts +293 -0
  493. package/src/mixins/OxyServices.identity.ts +705 -0
  494. package/src/mixins/OxyServices.identityBackup.ts +250 -0
  495. package/src/mixins/OxyServices.inference.ts +57 -0
  496. package/src/mixins/OxyServices.language.ts +144 -0
  497. package/src/mixins/OxyServices.links.ts +107 -0
  498. package/src/mixins/OxyServices.location.ts +46 -0
  499. package/src/mixins/OxyServices.nodes.ts +337 -0
  500. package/src/mixins/OxyServices.notifications.ts +142 -0
  501. package/src/mixins/OxyServices.payment.ts +163 -0
  502. package/src/mixins/OxyServices.privacy.ts +219 -0
  503. package/src/mixins/OxyServices.reputation.ts +436 -0
  504. package/src/mixins/OxyServices.security.ts +110 -0
  505. package/src/mixins/OxyServices.store.ts +585 -0
  506. package/src/mixins/OxyServices.topics.ts +169 -0
  507. package/src/mixins/OxyServices.user.ts +1137 -0
  508. package/src/mixins/OxyServices.utility.ts +1370 -0
  509. package/src/mixins/__tests__/OxyServices.civic.test.ts +1095 -0
  510. package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +124 -0
  511. package/src/mixins/__tests__/OxyServices.deviceTransfer.test.ts +271 -0
  512. package/src/mixins/__tests__/OxyServices.identity.test.ts +376 -0
  513. package/src/mixins/__tests__/OxyServices.links.test.ts +154 -0
  514. package/src/mixins/__tests__/OxyServices.nodes.test.ts +341 -0
  515. package/src/mixins/__tests__/OxyServices.rotateKey.test.ts +276 -0
  516. package/src/mixins/__tests__/OxyServices.serviceAssetMetadata.test.ts +192 -0
  517. package/src/mixins/__tests__/OxyServices.serviceAssetMetadataBySha.test.ts +135 -0
  518. package/src/mixins/__tests__/accounts.test.ts +727 -0
  519. package/src/mixins/__tests__/appData.test.ts +203 -0
  520. package/src/mixins/__tests__/assetCredentials.test.ts +47 -0
  521. package/src/mixins/__tests__/assetUpload.test.ts +191 -0
  522. package/src/mixins/__tests__/backgroundCredential.httpIntegration.test.ts +135 -0
  523. package/src/mixins/__tests__/chains.test.ts +113 -0
  524. package/src/mixins/__tests__/commonsSignIn.test.ts +1144 -0
  525. package/src/mixins/__tests__/connectedApps.test.ts +123 -0
  526. package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +113 -0
  527. package/src/mixins/__tests__/discoveryErrorHandling.test.ts +266 -0
  528. package/src/mixins/__tests__/followCacheInvalidation.test.ts +173 -0
  529. package/src/mixins/__tests__/followGraph.test.ts +147 -0
  530. package/src/mixins/__tests__/followGraphPagination.test.ts +271 -0
  531. package/src/mixins/__tests__/getFileDownloadUrl.test.ts +346 -0
  532. package/src/mixins/__tests__/getFollowStatuses.test.ts +95 -0
  533. package/src/mixins/__tests__/getUsersByIds.test.ts +149 -0
  534. package/src/mixins/__tests__/identityBackup.test.ts +315 -0
  535. package/src/mixins/__tests__/identityWriteCacheInvalidation.test.ts +407 -0
  536. package/src/mixins/__tests__/inferenceFactory.test.ts +58 -0
  537. package/src/mixins/__tests__/onTokensChanged.test.ts +129 -0
  538. package/src/mixins/__tests__/preSessionSkipAuth.test.ts +284 -0
  539. package/src/mixins/__tests__/privacyCacheInvalidation.test.ts +155 -0
  540. package/src/mixins/__tests__/reputation.test.ts +522 -0
  541. package/src/mixins/__tests__/serviceAuth.test.ts +832 -0
  542. package/src/mixins/__tests__/serviceTokenJwks.test.ts +208 -0
  543. package/src/mixins/__tests__/store.test.ts +304 -0
  544. package/src/mixins/__tests__/topics.test.ts +156 -0
  545. package/src/mixins/__tests__/userReadCacheBypass.test.ts +129 -0
  546. package/src/mixins/__tests__/userTokenAuth.test.ts +746 -0
  547. package/src/mixins/__tests__/verifyChallenge.test.ts +130 -0
  548. package/src/mixins/__tests__/verifyServiceActingAs.test.ts +167 -0
  549. package/src/mixins/__tests__/webauthnAuth.test.ts +205 -0
  550. package/src/mixins/index.ts +201 -0
  551. package/src/mixins/mixinHelpers.ts +69 -0
  552. package/src/models/Topic.ts +46 -0
  553. package/src/models/interfaces.ts +786 -0
  554. package/src/models/session.ts +55 -0
  555. package/src/server/__tests__/auth.test.ts +78 -0
  556. package/src/server/__tests__/capabilityTicket.test.ts +111 -0
  557. package/src/server/__tests__/cors.socket.test.ts +225 -0
  558. package/src/server/__tests__/cors.test.ts +158 -0
  559. package/src/server/__tests__/rateLimit.test.ts +257 -0
  560. package/src/server/__tests__/safeFetch.test.ts +232 -0
  561. package/src/server/__tests__/securityHeaders.test.ts +348 -0
  562. package/src/server/__tests__/serviceTokenAttribution.test.ts +396 -0
  563. package/src/server/__tests__/userInvalidation.test.ts +203 -0
  564. package/src/server/__tests__/verifySecret.test.ts +40 -0
  565. package/src/server/auth.ts +271 -0
  566. package/src/server/capabilityTicket.ts +258 -0
  567. package/src/server/cors.ts +277 -0
  568. package/src/server/index.ts +136 -0
  569. package/src/server/rateLimit.ts +313 -0
  570. package/src/server/safeFetch.ts +586 -0
  571. package/src/server/securityHeaders.ts +467 -0
  572. package/src/server/userInvalidation.ts +199 -0
  573. package/src/server/verifySecret.ts +52 -0
  574. package/src/session/SessionClient.ts +1001 -0
  575. package/src/session/__tests__/SessionClient.additive.test.ts +153 -0
  576. package/src/session/__tests__/SessionClient.broadcastChannel.test.ts +114 -0
  577. package/src/session/__tests__/SessionClient.diagnostics.test.ts +91 -0
  578. package/src/session/__tests__/SessionClient.directory.test.ts +688 -0
  579. package/src/session/__tests__/SessionClient.httpIntegration.test.ts +65 -0
  580. package/src/session/__tests__/SessionClient.identityPin.test.ts +175 -0
  581. package/src/session/__tests__/SessionClient.rest.test.ts +119 -0
  582. package/src/session/__tests__/SessionClient.serverEvents.test.ts +72 -0
  583. package/src/session/__tests__/SessionClient.socket.test.ts +202 -0
  584. package/src/session/__tests__/SessionClient.socketFactory.test.ts +81 -0
  585. package/src/session/__tests__/SessionClient.state.test.ts +78 -0
  586. package/src/session/__tests__/SessionClient.switchTokenOrder.test.ts +170 -0
  587. package/src/session/__tests__/accountDelegationAccess.test.ts +104 -0
  588. package/src/session/__tests__/accountDialogController.test.ts +1969 -0
  589. package/src/session/__tests__/accountDialogShape.test.ts +118 -0
  590. package/src/session/__tests__/accountSwitchTargets.test.ts +137 -0
  591. package/src/session/__tests__/authStateStore.test.ts +451 -0
  592. package/src/session/__tests__/deviceDirectory.test.ts +422 -0
  593. package/src/session/__tests__/deviceSwitcherRows.test.ts +223 -0
  594. package/src/session/__tests__/identityPin.test.ts +131 -0
  595. package/src/session/__tests__/identitySession.test.ts +194 -0
  596. package/src/session/__tests__/projectSessionState.test.ts +105 -0
  597. package/src/session/__tests__/refresh.identityPin.test.ts +307 -0
  598. package/src/session/__tests__/refresh.test.ts +443 -0
  599. package/src/session/__tests__/sessionIntegration.test.ts +209 -0
  600. package/src/session/__tests__/sharedDeviceCredential.test.ts +300 -0
  601. package/src/session/accountDelegationAccess.ts +72 -0
  602. package/src/session/accountDialogController.ts +1494 -0
  603. package/src/session/accountSwitchTargets.ts +93 -0
  604. package/src/session/authStateStore.ts +502 -0
  605. package/src/session/createSessionClient.ts +39 -0
  606. package/src/session/deviceDirectory.ts +269 -0
  607. package/src/session/deviceSwitcherRows.ts +145 -0
  608. package/src/session/identityPin.ts +310 -0
  609. package/src/session/identitySession.ts +206 -0
  610. package/src/session/projectSessionState.ts +137 -0
  611. package/src/session/refresh.ts +517 -0
  612. package/src/session/sessionClientHost.ts +39 -0
  613. package/src/session/sharedDeviceCredential.ts +349 -0
  614. package/src/session/socketLoader.ts +30 -0
  615. package/src/shared/utils/colorUtils.ts +155 -0
  616. package/src/shared/utils/errorUtils.ts +181 -0
  617. package/src/shared/utils/index.ts +59 -0
  618. package/src/shared/utils/networkUtils.ts +248 -0
  619. package/src/shared/utils/themeUtils.ts +115 -0
  620. package/src/types/buffer.d.ts +97 -0
  621. package/src/types/expo-crypto.d.ts +16 -0
  622. package/src/types/expo-secure-store.d.ts +17 -0
  623. package/src/utils/__tests__/accountUtils.test.ts +151 -0
  624. package/src/utils/__tests__/activityId.test.ts +45 -0
  625. package/src/utils/__tests__/asyncUtils.test.ts +187 -0
  626. package/src/utils/__tests__/authWebUrl.test.ts +15 -0
  627. package/src/utils/__tests__/cacheKey.test.ts +0 -0
  628. package/src/utils/__tests__/coldBoot.test.ts +496 -0
  629. package/src/utils/__tests__/commonsApproval.test.ts +60 -0
  630. package/src/utils/__tests__/identityCacheSweep.test.ts +151 -0
  631. package/src/utils/__tests__/languageUtils.test.ts +219 -0
  632. package/src/utils/__tests__/oauthPkce.test.ts +272 -0
  633. package/src/utils/__tests__/officialOrigins.test.ts +31 -0
  634. package/src/utils/__tests__/oxyServiceEnvironment.test.ts +7 -0
  635. package/src/utils/__tests__/profileLinks.test.ts +180 -0
  636. package/src/utils/__tests__/redactUrl.test.ts +33 -0
  637. package/src/utils/__tests__/registrableApex.test.ts +62 -0
  638. package/src/utils/__tests__/textNormalization.test.ts +205 -0
  639. package/src/utils/__tests__/validationUtils.test.ts +703 -0
  640. package/src/utils/__tests__/webauthnOrigin.test.ts +83 -0
  641. package/src/utils/accountCacheSweep.ts +93 -0
  642. package/src/utils/accountUtils.ts +194 -0
  643. package/src/utils/activityId.ts +2 -0
  644. package/src/utils/apiUtils.ts +137 -0
  645. package/src/utils/asyncUtils.ts +280 -0
  646. package/src/utils/authHelpers.ts +148 -0
  647. package/src/utils/authWebUrl.ts +17 -0
  648. package/src/utils/avatarUtils.ts +39 -0
  649. package/src/utils/cache.ts +273 -0
  650. package/src/utils/cacheKey.ts +93 -0
  651. package/src/utils/coldBoot.ts +218 -0
  652. package/src/utils/commonsApproval.ts +39 -0
  653. package/src/utils/commonsDelivery.ts +132 -0
  654. package/src/utils/deviceManager.ts +203 -0
  655. package/src/utils/displayNamePolicyRanges.generated.ts +69 -0
  656. package/src/utils/edgeRegion.ts +2 -0
  657. package/src/utils/errorUtils.ts +352 -0
  658. package/src/utils/identityCacheSweep.ts +104 -0
  659. package/src/utils/languageUtils.ts +256 -0
  660. package/src/utils/oauthPkce.ts +392 -0
  661. package/src/utils/officialOrigins.ts +62 -0
  662. package/src/utils/oxyServiceEnvironment.ts +17 -0
  663. package/src/utils/platform.ts +139 -0
  664. package/src/utils/profileLinks.ts +91 -0
  665. package/src/utils/redactUrl.ts +28 -0
  666. package/src/utils/registrableApex.ts +41 -0
  667. package/src/utils/requestUtils.ts +237 -0
  668. package/src/utils/sessionUtils.ts +206 -0
  669. package/src/utils/textNormalization.ts +162 -0
  670. package/src/utils/userHandle.ts +49 -0
  671. package/src/utils/userIdentity.ts +60 -0
  672. package/src/utils/validationUtils.ts +390 -0
  673. package/src/utils/webauthnOrigin.ts +52 -0
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The two questions an account chooser asks of an account-graph node: is this
3
+ * kind switchable at all, and may THIS caller become it.
4
+ *
5
+ * Pure and I/O-free. They live here rather than beside the surfaces that ask
6
+ * them because there is more than one such surface — the Console's workspace
7
+ * tree, the Accounts app's managed-account rows — and a second enumeration of
8
+ * switch targets is a second place for the rule to go missing, which is
9
+ * precisely how the Console went on offering `channel` rows after the rule
10
+ * learned to drop them.
11
+ *
12
+ * The DEVICE switcher no longer asks anything here: it renders the server's
13
+ * device directory (ADR 0002, `deviceDirectory.ts`), whose `available` field is
14
+ * the server's own authorization verdict. These predicates answer a different
15
+ * question — one about the caller's account GRAPH, which is a list of accounts
16
+ * to manage, not a list of identities the device can become.
17
+ */
18
+ import { isOperatorSwitchTargetKind } from '@oxy.so/contracts';
19
+ /**
20
+ * Whether the caller can BECOME this account — the one question every account
21
+ * switcher asks, answered here so no surface has to re-derive it.
22
+ *
23
+ * Two independent grounds, either of which suffices:
24
+ *
25
+ * - **It is already the caller's own identity** (`relationship: 'self'`).
26
+ * `GET /accounts` resolves its caller through `resolveOperatorId`, so `self`
27
+ * is the HUMAN operator's personal account even while they are operating an
28
+ * org — never the operated account. Kind is irrelevant on this ground: the
29
+ * caller IS that account, so returning to it asks the server for nothing.
30
+ * - **The server will mint a session for it** — `isOperatorSwitchTargetKind(kind)`
31
+ * is the exact predicate `POST /accounts/:id/switch` enforces, so a row
32
+ * offered on this ground is never a dead button.
33
+ *
34
+ * `isOperatorSwitchTargetKind` ALONE is not this question, and reaching for it
35
+ * directly is the mistake this function exists to prevent: it is false for
36
+ * `personal` as well as `channel`, so a switcher gated on it alone renders an
37
+ * empty list rather than a filtered one. Equally, `kind !== 'channel'` is not
38
+ * this question either — it silently admits every kind invented after it was
39
+ * written, which is the same trap the kind predicates were introduced to close
40
+ * on the server.
41
+ *
42
+ * And it is the OPERATOR predicate, never `isDelegatedActAsEligibleKind`. The
43
+ * two differ only on `bot`, so the delegated one produces a list that looks
44
+ * right and contains one row too many — a seat inside the identity that exists
45
+ * to act while nobody is present. That is not a hypothetical: it put a live bot
46
+ * session on a person's own device, beside their personal login.
47
+ *
48
+ * Takes a structural subset rather than a whole {@link AccountNode} so a caller
49
+ * holding an already-projected row can ask it too.
50
+ */
51
+ export function isSwitchTargetAccount(node) {
52
+ return node.relationship === 'self' || isOperatorSwitchTargetKind(node.kind);
53
+ }
54
+ /**
55
+ * Whether the caller may switch INTO this account — the server-side
56
+ * `account:act_as` gate plus the structural {@link isSwitchTargetAccount} rule.
57
+ *
58
+ * `relationship: 'self'` always passes (returning to the caller's own personal
59
+ * account). Every other ground requires a switch-eligible kind AND
60
+ * `account:act_as` in the resolved membership permissions. When permissions are
61
+ * absent but the relationship is `owner`, the owner baseline is assumed — the
62
+ * API always resolves effective permissions for owned accounts, but test
63
+ * fixtures and stale rows may omit the membership blob.
64
+ */
65
+ export function canSwitchIntoAccount(node) {
66
+ if (node.relationship === 'self') {
67
+ return true;
68
+ }
69
+ if (!isSwitchTargetAccount(node)) {
70
+ return false;
71
+ }
72
+ const permissions = node.callerMembership?.permissions;
73
+ if (permissions) {
74
+ return permissions.includes('account:act_as');
75
+ }
76
+ return node.relationship === 'owner';
77
+ }
@@ -0,0 +1,398 @@
1
+ /**
2
+ * Persisted auth state — ONE shape, web + native.
3
+ *
4
+ * The zero-cookie device transport persists the device credential per ORIGIN so
5
+ * a reload restores the session locally without a redirect: `deviceId` +
6
+ * `deviceSecret` mint a fresh access token via `POST /session/device/token`.
7
+ * This module is the storage seam: a tiny `load / save / clear` interface plus
8
+ * platform factories, so the cold boot (`sessionColdBoot`) and the unified re-mint
9
+ * handler (`refresh.ts`) never touch a platform storage API directly.
10
+ *
11
+ * Platform-agnostic — the native factory takes an INJECTED key/value store
12
+ * (`@oxy.so/services` passes a SecureStore-backed adapter) so `@oxy.so/core`
13
+ * never imports `expo-secure-store`. The web factory is self-contained
14
+ * (`localStorage`) and degrades to in-memory when storage is unavailable
15
+ * (sandboxed iframe `SecurityError`, private-mode quota, SSR).
16
+ *
17
+ * ESM-safe (no `require()`).
18
+ */
19
+ import { logger } from '../logger/index.js';
20
+ /**
21
+ * Versioned DURABLE storage key. Holds ONLY the small, re-mint-critical fields
22
+ * (`sessionId`, `userId`, `deviceId`, `deviceSecret`) — never the large JWT
23
+ * `accessToken`. Keeping this blob small (<2KB) matters on Android
24
+ * `expo-secure-store`, whose backing store can silently fail to persist an
25
+ * oversize value; bundling the token here previously took the mint credential
26
+ * down with it on every write, losing the session on cold restart.
27
+ *
28
+ * The `.v1` suffix lets a future shape change ship a `.v2` key without reading a
29
+ * stale/incompatible `.v1` blob. Distinct from the `oxy_shared_*` keychain keys
30
+ * in `KeyManager`, so it never collides.
31
+ *
32
+ * BACK-COMPAT: pre-split builds wrote the WHOLE state (including `accessToken` /
33
+ * `expiresAt`) into this single key. `load()` still reads those token fields
34
+ * from here when the warm key ({@link AUTH_STATE_TOKEN_STORAGE_KEY}) is absent,
35
+ * so upgrading users are not signed out; the next `save()` splits them apart.
36
+ */
37
+ export const AUTH_STATE_STORAGE_KEY = 'oxy.auth.v1';
38
+ /**
39
+ * Versioned BEST-EFFORT warm-token storage key. Holds the short-lived
40
+ * `{ accessToken, expiresAt }` pair only. Its write is genuinely non-fatal — a
41
+ * failure (quota / oversize keychain value) is swallowed because the session is
42
+ * fully re-mintable from the durable `deviceSecret`. Kept separate from
43
+ * {@link AUTH_STATE_STORAGE_KEY} so a failed token write can NEVER abort or
44
+ * corrupt the durable credential write.
45
+ */
46
+ export const AUTH_STATE_TOKEN_STORAGE_KEY = 'oxy.auth.token.v1';
47
+ /**
48
+ * Parse + shape-validate a stored blob. Returns `null` for anything that is
49
+ * not a well-formed {@link PersistedAuthState} (absent, malformed JSON, wrong
50
+ * types) so a corrupt entry degrades to "signed out" rather than throwing.
51
+ */
52
+ function deserialize(raw) {
53
+ if (!raw) {
54
+ return null;
55
+ }
56
+ let parsed;
57
+ try {
58
+ parsed = JSON.parse(raw);
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ if (!parsed || typeof parsed !== 'object') {
64
+ return null;
65
+ }
66
+ const candidate = parsed;
67
+ const hasDeviceCredential = typeof candidate.deviceId === 'string' &&
68
+ candidate.deviceId.length > 0 &&
69
+ typeof candidate.deviceSecret === 'string' &&
70
+ candidate.deviceSecret.length > 0;
71
+ const hasSessionIdentity = typeof candidate.sessionId === 'string' &&
72
+ typeof candidate.userId === 'string' &&
73
+ candidate.sessionId.length > 0 &&
74
+ candidate.userId.length > 0;
75
+ // Device-only bootstrap (post join, pre-sign-in): durable credential without session.
76
+ if (!hasSessionIdentity && !hasDeviceCredential) {
77
+ return null;
78
+ }
79
+ const state = {
80
+ sessionId: hasSessionIdentity ? candidate.sessionId : '',
81
+ userId: hasSessionIdentity ? candidate.userId : '',
82
+ };
83
+ if (typeof candidate.deviceId === 'string' && candidate.deviceId.length > 0) {
84
+ state.deviceId = candidate.deviceId;
85
+ }
86
+ if (typeof candidate.deviceSecret === 'string' && candidate.deviceSecret.length > 0) {
87
+ state.deviceSecret = candidate.deviceSecret;
88
+ }
89
+ if (typeof candidate.accessToken === 'string' && candidate.accessToken.length > 0) {
90
+ state.accessToken = candidate.accessToken;
91
+ }
92
+ if (typeof candidate.expiresAt === 'string' && candidate.expiresAt.length > 0) {
93
+ state.expiresAt = candidate.expiresAt;
94
+ }
95
+ return state;
96
+ }
97
+ /**
98
+ * Parse the best-effort warm-token blob. Returns `null` for anything not a
99
+ * well-formed object so a corrupt warm entry simply forgoes the warm-boot
100
+ * optimization (the durable credential re-mints a fresh token).
101
+ */
102
+ function parseWarmToken(raw) {
103
+ if (!raw) {
104
+ return null;
105
+ }
106
+ let parsed;
107
+ try {
108
+ parsed = JSON.parse(raw);
109
+ }
110
+ catch {
111
+ return null;
112
+ }
113
+ if (!parsed || typeof parsed !== 'object') {
114
+ return null;
115
+ }
116
+ const candidate = parsed;
117
+ const warm = {};
118
+ if (typeof candidate.accessToken === 'string' && candidate.accessToken.length > 0) {
119
+ warm.accessToken = candidate.accessToken;
120
+ }
121
+ if (typeof candidate.expiresAt === 'string' && candidate.expiresAt.length > 0) {
122
+ warm.expiresAt = candidate.expiresAt;
123
+ }
124
+ return warm;
125
+ }
126
+ /** Serialize ONLY the small, re-mint-critical fields for the durable key. */
127
+ function serializeDurable(state) {
128
+ const durable = {
129
+ sessionId: state.sessionId,
130
+ userId: state.userId,
131
+ };
132
+ if (state.deviceId) {
133
+ durable.deviceId = state.deviceId;
134
+ }
135
+ if (state.deviceSecret) {
136
+ durable.deviceSecret = state.deviceSecret;
137
+ }
138
+ return JSON.stringify(durable);
139
+ }
140
+ /**
141
+ * Serialize the warm-token blob, or `null` when there is no token to persist
142
+ * (so the caller clears the warm key rather than writing an empty object).
143
+ */
144
+ function serializeWarmToken(state) {
145
+ const warm = {};
146
+ if (state.accessToken) {
147
+ warm.accessToken = state.accessToken;
148
+ }
149
+ if (state.expiresAt) {
150
+ warm.expiresAt = state.expiresAt;
151
+ }
152
+ if (!warm.accessToken && !warm.expiresAt) {
153
+ return null;
154
+ }
155
+ return JSON.stringify(warm);
156
+ }
157
+ /**
158
+ * Compose the unchanged {@link PersistedAuthState} return shape from the two
159
+ * on-disk keys. `accessToken` / `expiresAt` come from the warm key when it is
160
+ * present; when the warm key is ABSENT the token fields fall back to whatever
161
+ * the durable blob carried — the pre-split combined `oxy.auth.v1` blob (BACK-COMPAT).
162
+ */
163
+ function composeState(durableRaw, warmRaw) {
164
+ const state = deserialize(durableRaw);
165
+ if (!state) {
166
+ return null;
167
+ }
168
+ if (warmRaw !== null) {
169
+ // New split layout: the warm key is authoritative for the token fields.
170
+ // Drop anything the durable blob may have carried, then overlay the warm
171
+ // values (a warm key with no token → the session simply has no warm token).
172
+ delete state.accessToken;
173
+ delete state.expiresAt;
174
+ const warm = parseWarmToken(warmRaw);
175
+ if (warm?.accessToken) {
176
+ state.accessToken = warm.accessToken;
177
+ }
178
+ if (warm?.expiresAt) {
179
+ state.expiresAt = warm.expiresAt;
180
+ }
181
+ }
182
+ // else: BACK-COMPAT — the warm key is absent, so `deserialize` already applied
183
+ // any `accessToken` / `expiresAt` from the old combined blob.
184
+ return state;
185
+ }
186
+ /**
187
+ * A process-lifetime, in-memory {@link AuthStateStore}. Used directly for
188
+ * tests/SSR and as the degraded fallback of the web store when `localStorage`
189
+ * is unreachable. Not durable across reloads — that is acceptable for the
190
+ * fallback because the alternative (throwing) would break cold boot entirely.
191
+ */
192
+ export function createMemoryAuthStateStore() {
193
+ let current = null;
194
+ return {
195
+ load: async () => current,
196
+ save: async (state) => {
197
+ // Memory IS this store's durability backing — the write always lands.
198
+ current = state;
199
+ return true;
200
+ },
201
+ clear: async () => {
202
+ current = null;
203
+ },
204
+ };
205
+ }
206
+ /**
207
+ * Read the ambient `localStorage`, tolerating the case where merely ACCESSING
208
+ * `window.localStorage` throws. In a sandboxed / cross-origin iframe the getter
209
+ * itself raises `SecurityError` (not the method calls), so the access must be
210
+ * inside the try. Returns `null` when storage is unavailable.
211
+ */
212
+ function safeGetLocalStorage() {
213
+ try {
214
+ if (typeof globalThis === 'undefined') {
215
+ return null;
216
+ }
217
+ const store = globalThis.localStorage;
218
+ return store ?? null;
219
+ }
220
+ catch {
221
+ return null;
222
+ }
223
+ }
224
+ /**
225
+ * A `localStorage`-backed {@link AuthStateStore} split across the durable
226
+ * {@link AUTH_STATE_STORAGE_KEY} (mint credential) and the best-effort
227
+ * {@link AUTH_STATE_TOKEN_STORAGE_KEY} (warm access token).
228
+ *
229
+ * Resilience:
230
+ * - If `localStorage` is unreachable (sandboxed-iframe `SecurityError`, SSR),
231
+ * the whole store degrades to an in-memory {@link createMemoryAuthStateStore}
232
+ * for this page's lifetime — never throws on construction.
233
+ * - Individual `getItem`/`setItem`/`removeItem` are each wrapped: a read that
234
+ * throws yields `null`; a write that throws (quota, private mode) is
235
+ * swallowed. The re-mint lane treats a failed persist as "no durable state"
236
+ * rather than crashing.
237
+ */
238
+ export function createWebAuthStateStore() {
239
+ const storage = safeGetLocalStorage();
240
+ if (!storage) {
241
+ return createMemoryAuthStateStore();
242
+ }
243
+ // In-memory mirror so a FAILED persist (quota / private mode / locked store)
244
+ // does not silently lose the session for this page's lifetime. `undefined`
245
+ // means "never written this session" → fall back to storage; any set value
246
+ // (including `null` after clear) is authoritative and preferred over storage.
247
+ let sessionMirror;
248
+ return {
249
+ load: async () => {
250
+ if (sessionMirror !== undefined) {
251
+ return sessionMirror;
252
+ }
253
+ try {
254
+ return composeState(storage.getItem(AUTH_STATE_STORAGE_KEY), storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY));
255
+ }
256
+ catch {
257
+ return null;
258
+ }
259
+ },
260
+ save: async (state) => {
261
+ sessionMirror = state; // mirror FIRST — authoritative even if persist fails
262
+ // Durable credential FIRST, then VERIFY it landed. The in-memory mirror
263
+ // keeps the session live for this page, but a failed DURABLE write means
264
+ // the mint credential will NOT survive a reload — surface it, never swallow.
265
+ let durablePersisted = false;
266
+ try {
267
+ const durableJson = serializeDurable(state);
268
+ storage.setItem(AUTH_STATE_STORAGE_KEY, durableJson);
269
+ durablePersisted = storage.getItem(AUTH_STATE_STORAGE_KEY) === durableJson;
270
+ if (!durablePersisted) {
271
+ logger.error('[authStateStore] durable credential read-back mismatch after save — the device credential did not persist; the session survives this process via the in-memory mirror but will be lost on reload', undefined, { component: 'authStateStore' });
272
+ }
273
+ }
274
+ catch (error) {
275
+ logger.error('[authStateStore] durable credential persist threw — the device credential did not persist; the session survives this process via the in-memory mirror but will be lost on reload', error, { component: 'authStateStore' });
276
+ }
277
+ // Warm token AFTER, best-effort. Its failure is genuinely non-fatal (the
278
+ // durable credential re-mints a fresh token) and must never abort or
279
+ // corrupt the durable write above.
280
+ try {
281
+ const warmJson = serializeWarmToken(state);
282
+ if (warmJson) {
283
+ storage.setItem(AUTH_STATE_TOKEN_STORAGE_KEY, warmJson);
284
+ }
285
+ else {
286
+ storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
287
+ }
288
+ }
289
+ catch {
290
+ // Quota / private-mode / disabled storage — non-fatal warm-boot loss only.
291
+ }
292
+ // Report ONLY the durable-credential landing; the warm-token outcome above
293
+ // is intentionally excluded (it is a best-effort optimization).
294
+ return durablePersisted;
295
+ },
296
+ clear: async () => {
297
+ sessionMirror = null;
298
+ try {
299
+ storage.removeItem(AUTH_STATE_STORAGE_KEY);
300
+ }
301
+ catch {
302
+ // Non-fatal — see save().
303
+ }
304
+ try {
305
+ storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
306
+ }
307
+ catch {
308
+ // Non-fatal — see save().
309
+ }
310
+ },
311
+ };
312
+ }
313
+ /**
314
+ * A native {@link AuthStateStore} over an injected async key/value store.
315
+ *
316
+ * `@oxy.so/core` never imports `expo-secure-store`; `@oxy.so/services` constructs
317
+ * the SecureStore-backed adapter and passes it here. Persistence is split across
318
+ * the durable {@link AUTH_STATE_STORAGE_KEY} (mint credential) and the
319
+ * best-effort {@link AUTH_STATE_TOKEN_STORAGE_KEY} (warm access token) — the
320
+ * durable write is read-back-verified and its failure surfaced (not swallowed),
321
+ * while the warm-token write and all reads degrade gracefully exactly like the
322
+ * web store.
323
+ */
324
+ export function createNativeAuthStateStore(storage) {
325
+ // Same in-memory mirror as the web store — a locked/failed SecureStore write
326
+ // must not silently lose the session for the app's lifetime.
327
+ let sessionMirror;
328
+ return {
329
+ load: async () => {
330
+ if (sessionMirror !== undefined) {
331
+ return sessionMirror;
332
+ }
333
+ try {
334
+ const [durableRaw, warmRaw] = await Promise.all([
335
+ storage.getItem(AUTH_STATE_STORAGE_KEY),
336
+ storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY),
337
+ ]);
338
+ return composeState(durableRaw, warmRaw);
339
+ }
340
+ catch {
341
+ return null;
342
+ }
343
+ },
344
+ save: async (state) => {
345
+ sessionMirror = state;
346
+ // Durable credential FIRST, then VERIFY. On Android SecureStore an
347
+ // oversize/failed write can resolve WITHOUT throwing, so a read-back is the
348
+ // only reliable proof. The mirror keeps the session live for this app run,
349
+ // but a failed DURABLE write means the mint credential will NOT survive a
350
+ // cold restart — surface it, never swallow.
351
+ let durablePersisted = false;
352
+ try {
353
+ const durableJson = serializeDurable(state);
354
+ await storage.setItem(AUTH_STATE_STORAGE_KEY, durableJson);
355
+ durablePersisted = (await storage.getItem(AUTH_STATE_STORAGE_KEY)) === durableJson;
356
+ if (!durablePersisted) {
357
+ logger.error('[authStateStore] durable credential read-back mismatch after save — the device credential did not persist (likely oversize SecureStore value); the session survives this app run via the in-memory mirror but will be lost on cold restart', undefined, { component: 'authStateStore' });
358
+ }
359
+ }
360
+ catch (error) {
361
+ logger.error('[authStateStore] durable credential persist threw — the device credential did not persist; the session survives this app run via the in-memory mirror but will be lost on cold restart', error, { component: 'authStateStore' });
362
+ }
363
+ // Warm token AFTER, best-effort. Its failure is genuinely non-fatal (the
364
+ // durable credential re-mints a fresh token) and must never abort or
365
+ // corrupt the durable write above.
366
+ try {
367
+ const warmJson = serializeWarmToken(state);
368
+ if (warmJson) {
369
+ await storage.setItem(AUTH_STATE_TOKEN_STORAGE_KEY, warmJson);
370
+ }
371
+ else {
372
+ await storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
373
+ }
374
+ }
375
+ catch {
376
+ // Locked / oversize keychain — non-fatal warm-boot loss only.
377
+ }
378
+ // Report ONLY the durable-credential landing; the warm-token outcome above
379
+ // is intentionally excluded (it is a best-effort optimization).
380
+ return durablePersisted;
381
+ },
382
+ clear: async () => {
383
+ sessionMirror = null;
384
+ try {
385
+ await storage.removeItem(AUTH_STATE_STORAGE_KEY);
386
+ }
387
+ catch {
388
+ // Non-fatal.
389
+ }
390
+ try {
391
+ await storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
392
+ }
393
+ catch {
394
+ // Non-fatal.
395
+ }
396
+ },
397
+ };
398
+ }
@@ -0,0 +1,29 @@
1
+ import { SessionClient } from './SessionClient.js';
2
+ import { createSessionClientHost } from './sessionClientHost.js';
3
+ /**
4
+ * Wires a `SessionClient` over the given `OxyServices` instance: builds the
5
+ * `SessionClientHost` adapter and passes it through together with a
6
+ * caller-supplied `TokenTransport`.
7
+ *
8
+ * The transport is a required parameter (not constructed here) because it is
9
+ * the one piece of this integration that is NOT platform-agnostic: `services`
10
+ * branches native (shared-keychain sign-in) vs. web (silent sign-in), while
11
+ * `auth-sdk` is web-only. Each consumer builds its own transport and passes
12
+ * it in; this factory only wires the platform-agnostic parts (host + client)
13
+ * so neither consumer re-implements them.
14
+ *
15
+ * The host is returned alongside the client (not just the client) so the
16
+ * caller can call `host.setCurrentAccountId(...)` as the active account
17
+ * changes.
18
+ *
19
+ * `socketFactory` is the statically-injected `socket.io-client` `io` export.
20
+ * Consumers that bundle socket.io-client as a real dependency pass it so
21
+ * realtime sync never depends on core's lazy dynamic import of a bare
22
+ * specifier (bundler-fragile in Metro/Expo-web and Vite against the published
23
+ * dist). When omitted, the client falls back to the lazy loader.
24
+ */
25
+ export function createSessionClient(oxyServices, transport, socketFactory) {
26
+ const host = createSessionClientHost(oxyServices);
27
+ const client = new SessionClient(host, { transport, socketFactory });
28
+ return { client, host };
29
+ }
@@ -0,0 +1,135 @@
1
+ import { getAccountDisplayName } from '../utils/accountUtils.js';
2
+ import { getNormalizedUserHandle } from '../utils/userHandle.js';
3
+ /** Resolve one wire context under the principal it hangs off. */
4
+ function toDeviceContext(principal, context) {
5
+ return {
6
+ contextId: context.id,
7
+ actor: {
8
+ principalId: principal.id,
9
+ userId: principal.userId,
10
+ authuser: principal.authuser,
11
+ profile: principal.user,
12
+ },
13
+ subject: {
14
+ accountId: context.accountId,
15
+ kind: context.kind,
16
+ relationship: context.relationship,
17
+ profile: context.account,
18
+ onDevice: context.onDevice,
19
+ available: context.available,
20
+ lastUsedAt: context.lastUsedAt,
21
+ },
22
+ isDelegated: context.accountId !== principal.userId,
23
+ };
24
+ }
25
+ /**
26
+ * Resolve one context by its id.
27
+ *
28
+ * The search is over `(principal, context)` PAIRS, not over accounts: the same
29
+ * `accountId` legitimately appears under two principals on a shared device, and
30
+ * matching on the account would hand back whichever person happened to be
31
+ * enumerated first.
32
+ */
33
+ export function resolveDeviceContext(directory, contextId) {
34
+ if (directory === null) {
35
+ return null;
36
+ }
37
+ for (const principal of directory.principals) {
38
+ for (const context of principal.contexts) {
39
+ if (context.id === contextId) {
40
+ return toDeviceContext(principal, context);
41
+ }
42
+ }
43
+ }
44
+ return null;
45
+ }
46
+ /**
47
+ * The directory as the switcher renders it: people, each with what they may
48
+ * become.
49
+ *
50
+ * A principal with no contexts is kept rather than dropped. It is a real state
51
+ * — a person whose every context was removed while they remain on the device —
52
+ * and rendering them with nothing under them is how "sign out of this person"
53
+ * stays reachable. Silently omitting them would strand the row.
54
+ */
55
+ export function projectDevicePrincipals(directory) {
56
+ if (directory === null) {
57
+ return [];
58
+ }
59
+ return directory.principals.map((principal) => ({
60
+ principalId: principal.id,
61
+ userId: principal.userId,
62
+ authuser: principal.authuser,
63
+ profile: principal.user,
64
+ contexts: principal.contexts.map((context) => toDeviceContext(principal, context)),
65
+ isActive: directory.activeContextId !== null &&
66
+ principal.contexts.some((context) => context.id === directory.activeContextId),
67
+ }));
68
+ }
69
+ /**
70
+ * The device's active context, or `null`.
71
+ *
72
+ * `null` is a real state, not an error: a device with every context removed, or
73
+ * one whose active context was healed away, has none. It is also the answer when
74
+ * `activeContextId` names a row no principal holds — a directory that
75
+ * disagreed with itself, which resolves to "nothing is active" rather than to a
76
+ * guess.
77
+ */
78
+ export function resolveActiveContext(directory) {
79
+ if (directory === null || directory.activeContextId === null) {
80
+ return null;
81
+ }
82
+ return resolveDeviceContext(directory, directory.activeContextId);
83
+ }
84
+ /**
85
+ * The name a directory row renders: the API's `displayName` when it has one,
86
+ * otherwise the normalized handle, otherwise the localized unnamed sentinel.
87
+ *
88
+ * The identity contract's `displayName ?? handle`, and deliberately not
89
+ * `getAccountDisplayName`'s multi-field chain — that one is for LOCAL account
90
+ * surfaces, and the directory profile is an API DTO whose `name.displayName`
91
+ * the server already composed or deliberately omitted. `getAccountDisplayName`
92
+ * appears here only for its `null` case, which is the sentinel.
93
+ */
94
+ export function directoryDisplayName(profile, locale) {
95
+ const displayName = profile.name?.displayName?.trim();
96
+ if (displayName) {
97
+ return displayName;
98
+ }
99
+ return getNormalizedUserHandle(profile) ?? getAccountDisplayName(null, locale);
100
+ }
101
+ /**
102
+ * A directory row's `@handle`, or `null` when the profile carries no usable
103
+ * username.
104
+ *
105
+ * The directory profile has no email — by design, it is the minimum that
106
+ * renders a row — so the handle is the secondary line, never a synthesized
107
+ * `username@oxy.so` address.
108
+ */
109
+ export function directoryHandle(profile) {
110
+ return getNormalizedUserHandle(profile);
111
+ }
112
+ /**
113
+ * Whether a switcher may offer this row — the one question it asks, answered
114
+ * here so no surface has to re-derive it.
115
+ *
116
+ * It is deliberately a single field. `available` is the server's complete
117
+ * verdict (see {@link DeviceContextSubject.available}), and switchability is an
118
+ * authorization question the client must READ, never recompute; this exists to
119
+ * name the field that answers it, not to combine several.
120
+ *
121
+ * `onDevice` is NOT part of the question and composing the two is the mistake
122
+ * this function exists to prevent, in both directions. `onDevice: false` is an
123
+ * ordinary reachable context whose session is minted on first activation, so
124
+ * requiring it hides every organization the person has not used here yet.
125
+ * `onDevice: true` does not imply activatable either: when a principal's own
126
+ * personal session dies, their delegated contexts keep live sessions of their
127
+ * own and still cannot be activated, so `available || onDevice` would render a
128
+ * row the server answers with 403 and then heals away.
129
+ *
130
+ * Takes a structural subset so a caller holding a raw `DeviceAccountContext`
131
+ * from the wire can ask it without resolving the pair first.
132
+ */
133
+ export function canActivateContext(context) {
134
+ return context.available;
135
+ }