@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,1131 @@
1
+ "use strict";
2
+ /**
3
+ * Headless controller for the unified Oxy account dialog.
4
+ *
5
+ * A framework-agnostic state machine + subscribe/getSnapshot store (the same
6
+ * pattern {@link SessionClient} uses — no React, no RN) that both
7
+ * every `OxyProvider` platform variant (Expo/RN and RN-Web)
8
+ * bind to via `useSyncExternalStore`, so the account chooser is ONE
9
+ * implementation across the ecosystem instead of the five drifting copies it
10
+ * replaces.
11
+ *
12
+ * The controller owns:
13
+ * - the device DIRECTORY (ADR 0002) — the server-authoritative read model of
14
+ * who is on this device and what each of them may act as, read through
15
+ * `SessionClient.refreshDirectory()`. It is not assembled here: the client
16
+ * holds one caller's account graph and cannot enumerate another principal's,
17
+ * so switchability is the server's answer and the controller only reads it;
18
+ * - the dialog `view` state machine (`accounts` | `signin` | `qr` | `add` |
19
+ * `signup`);
20
+ * - `activateContext` (the ADR 0002 switch, keyed on the `principal acting as
21
+ * account` pair) and the two removals an account id cannot name —
22
+ * `signOutContext` and `signOutPrincipal`;
23
+ * - the "Sign in with Oxy" device flow (same-device shared-keychain via
24
+ * `oxyServices.signInWithSharedIdentity`, else the cross-device QR handoff
25
+ * via `startCommonsSignIn` → poll → `claimSessionByToken`);
26
+ * - AUTOMATIC delivery selection for that flow (issue #691): the user presses
27
+ * ONE primary action and the controller — not the user — picks how the
28
+ * request reaches their Commons identity, by gathering the facts
29
+ * (`platform`, `commonsAvailability`, and the `targets` a bearer-authorized
30
+ * `deliverCommonsSignIn` reached) and handing them to the pure
31
+ * `selectCommonsDelivery`. Exactly one route is primary; alternatives are
32
+ * never chained behind it, they are state (`signIn.route`,
33
+ * `signIn.routeFailed`) the UI reveals on its own terms;
34
+ * - honest, non-sensitive PROGRESS for that flow (`signIn.progress`), derived
35
+ * only from real signals — the chosen route, `pushSentAt`, `openedAt`,
36
+ * `authorized`, and the commit — never from an optimistic timeline;
37
+ * - `commonsAvailability` — whether Commons is installed on this device
38
+ * (native only, via the injected `canOpenApp` probe), so the QR view can
39
+ * offer a "Get Commons" fallback instead of a same-device dead end.
40
+ * - `startPasskeyHubSignIn` — on a non-Oxy web origin (where a WebAuthn
41
+ * ceremony can't run locally, the RP-ID is bound to oxy.so), open a popup
42
+ * at the auth.oxy.so passkey hub instead, scoped to the SAME device-flow
43
+ * session `showQr` creates, and complete it via the SAME poll/socket/claim
44
+ * engine. Falls back to `showQr`'s plain QR rendering if the popup is
45
+ * blocked.
46
+ *
47
+ * Sign-in is passkey (WebAuthn) or the Commons QR / shared-keychain handoff —
48
+ * password, social login, and 2FA were removed ecosystem-wide. Account
49
+ * creation (`signup` view) is the same two identity backends: a passkey
50
+ * ceremony on web, or a Commons-created identity.
51
+ *
52
+ * The controller owns NO surface PRESENTATION: whether the account dialog is
53
+ * mounted, visible, or dismissed is the job of the shared surface stack
54
+ * (`@oxy.so/services` presents the `AccountDialog` surface into `@oxy.so/bloom`'s
55
+ * stack). This is a headless state machine only — it exposes `setView` /
56
+ * `add` / `startSignup` (the view axis) and `cancelSignIn` (device-flow
57
+ * teardown), never an `open` / `close` / `visible`.
58
+ */
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ exports.AccountDialogController = void 0;
61
+ exports.createAccountDialogController = createAccountDialogController;
62
+ const logger_1 = require("../logger");
63
+ const errorUtils_1 = require("../utils/errorUtils");
64
+ const authWebUrl_1 = require("../utils/authWebUrl");
65
+ const socketLoader_1 = require("./socketLoader");
66
+ const deviceDirectory_1 = require("./deviceDirectory");
67
+ const commonsDelivery_1 = require("../utils/commonsDelivery");
68
+ /**
69
+ * Derive the surface-facing progress from the flow's real facts. Pure, total,
70
+ * and the single place the ladder is defined.
71
+ *
72
+ * Ordering within `'waiting'` is most-specific-first, so a late-arriving weaker
73
+ * signal can never pull the display backwards.
74
+ */
75
+ function deriveSignInProgress(facts) {
76
+ switch (facts.phase) {
77
+ case 'idle':
78
+ case 'error':
79
+ return 'idle';
80
+ case 'starting':
81
+ return 'preparing';
82
+ case 'authorized':
83
+ return 'confirming-identity';
84
+ case 'completed':
85
+ return 'identity-confirmed';
86
+ case 'waiting':
87
+ if (facts.openedAt !== null)
88
+ return 'opened-in-commons';
89
+ // `route === 'await-push'` is itself a server-confirmed dispatch (the
90
+ // route is only chosen when `deliverCommonsSignIn` reported ≥1 target),
91
+ // so it is a real signal — not an optimistic assumption that a push will
92
+ // arrive. `pushSentAt` is the same fact re-confirmed by the status poll.
93
+ if (facts.pushSentAt !== null || facts.route === 'await-push')
94
+ return 'delivered-to-commons';
95
+ return facts.route === null ? 'preparing' : 'awaiting-approval';
96
+ }
97
+ }
98
+ /**
99
+ * Slow FALLBACK poll cadence for the QR flow. The `/auth-session` socket delivers
100
+ * the approval instantly via `auth_update`; this poll only covers the case where
101
+ * the socket can't connect, so it is deliberately slow (was 3000 when polling was
102
+ * the sole mechanism).
103
+ */
104
+ const DEFAULT_POLL_INTERVAL_MS = 12000;
105
+ /** Socket.IO namespace the API emits QR-flow approval (`auth_update`) events on. */
106
+ const AUTH_SESSION_NAMESPACE = '/auth-session';
107
+ /**
108
+ * Commons's custom URL scheme. Probed via the injected `canOpenApp` to detect an
109
+ * installed Commons on the same device; the `oxycommons://approve?...` deep link
110
+ * itself is the flow's `qrPayload`.
111
+ */
112
+ const COMMONS_APP_SCHEME = 'oxycommons://';
113
+ const IDLE_SIGN_IN_FACTS = {
114
+ phase: 'idle',
115
+ authorizeCode: null,
116
+ qrPayload: null,
117
+ expiresAt: null,
118
+ error: null,
119
+ route: null,
120
+ routeFailed: false,
121
+ pushSentAt: null,
122
+ openedAt: null,
123
+ };
124
+ const IDLE_SIGN_IN = {
125
+ ...IDLE_SIGN_IN_FACTS,
126
+ progress: deriveSignInProgress(IDLE_SIGN_IN_FACTS),
127
+ };
128
+ /**
129
+ * Terminal SUCCESS state: the session was claimed and committed. Holds no live
130
+ * resources and no request handles — only the terminal progress the surface
131
+ * shows ("Identity confirmed") before it closes.
132
+ */
133
+ const COMPLETED_SIGN_IN = {
134
+ ...IDLE_SIGN_IN_FACTS,
135
+ phase: 'completed',
136
+ progress: deriveSignInProgress({ ...IDLE_SIGN_IN_FACTS, phase: 'completed' }),
137
+ };
138
+ function errorMessage(error) {
139
+ return error instanceof Error ? error.message : String(error);
140
+ }
141
+ class AccountDialogController {
142
+ constructor(options) {
143
+ this.listeners = new Set();
144
+ // --- Internal (unprojected) state ---
145
+ this.view = 'accounts';
146
+ this.loading = false;
147
+ this.error = null;
148
+ this.activatingContextId = null;
149
+ this.removingContextId = null;
150
+ this.removingPrincipalId = null;
151
+ this.signIn = IDLE_SIGN_IN;
152
+ this.commonsAvailability = 'unknown';
153
+ // --- Sign-in device-flow bookkeeping ---
154
+ /** The secret device-flow token of the active QR flow (never surfaced). */
155
+ this.signInToken = null;
156
+ this.pollTimer = null;
157
+ /**
158
+ * The `/auth-session` socket for the active QR flow, or null (poll-only). Its
159
+ * `auth_update` event wakes {@link pollOnce} instantly instead of waiting for the
160
+ * slow fallback timer.
161
+ */
162
+ this.authSessionSocket = null;
163
+ /**
164
+ * Guards {@link pollOnce} against re-entrancy: the fallback timer and a socket
165
+ * `auth_update` wake can fire together — without this both could claim the
166
+ * single-use token concurrently.
167
+ */
168
+ this.pollInFlight = false;
169
+ /** The popup opened by {@link startPasskeyHubSignIn}, or `null`. */
170
+ this.activePopup = null;
171
+ /** Watches {@link activePopup}'s `closed` state; see {@link watchPopup}. */
172
+ this.popupWatchTimer = null;
173
+ // --- Store plumbing ---
174
+ this.unsubscribeSession = null;
175
+ this.unsubscribeTokens = null;
176
+ /** Last-observed SDK auth readiness (a planted bearer). Drives the fetch edge. */
177
+ this.authed = false;
178
+ this.started = false;
179
+ this.refreshSeq = 0;
180
+ this.oxyServices = options.oxyServices;
181
+ this.sessionClient = options.sessionClient;
182
+ this.clientId = options.clientId ?? null;
183
+ this.commitSession = options.commitSession;
184
+ this.onSignedIn = options.onSignedIn;
185
+ this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
186
+ this.openUrl = options.openUrl;
187
+ this.canOpenApp = options.canOpenApp;
188
+ this.socketFactory = options.socketFactory;
189
+ this.openPopup = options.openPopup;
190
+ this.hubBaseUrl = options.hubBaseUrl ?? `https://auth.${authWebUrl_1.CENTRAL_IDP_APEX}`;
191
+ this.platform = options.platform ?? 'unknown';
192
+ this.snapshot = this.computeSnapshot();
193
+ }
194
+ // =========================================================================
195
+ // Store surface (useSyncExternalStore)
196
+ // =========================================================================
197
+ /** Returns the current immutable snapshot (stable reference between changes). */
198
+ getSnapshot() {
199
+ return this.snapshot;
200
+ }
201
+ /** Subscribe to snapshot changes. Returns an unsubscribe function. */
202
+ subscribe(listener) {
203
+ this.listeners.add(listener);
204
+ return () => {
205
+ this.listeners.delete(listener);
206
+ };
207
+ }
208
+ // =========================================================================
209
+ // Lifecycle
210
+ // =========================================================================
211
+ /**
212
+ * Begin driving the dialog: subscribe to `SessionClient` state and load the
213
+ * account list. Idempotent — a second `start()` is a no-op. Pair with
214
+ * {@link destroy}.
215
+ */
216
+ start() {
217
+ if (this.started)
218
+ return;
219
+ this.started = true;
220
+ this.authed = this.isAuthenticated();
221
+ this.unsubscribeSession = this.sessionClient.subscribe(() => {
222
+ // A device change (switch / sign-out / sibling sign-in) re-reads the
223
+ // directory inside `SessionClient` before it notifies, so the snapshot
224
+ // this rebuilds is already the new one — publish it and reconcile the
225
+ // auth-readiness edge. No profile fetch: the directory carries the display
226
+ // metadata a row needs.
227
+ this.emit();
228
+ this.reconcileAuth();
229
+ });
230
+ // The access token is planted AFTER `SessionClient.applyState` fires its
231
+ // subscription (`applySync` calls `setTokens` only once `applyState`/notify
232
+ // has returned; `ensureActiveToken` plants it async later), so the
233
+ // device-state subscription alone cannot observe the signed-out → signed-in
234
+ // edge. Observe the SDK-canonical readiness signal directly — a change to
235
+ // `oxyServices.getAccessToken()`, the `hasAccessToken` term of
236
+ // `OxyContext.canUsePrivateApi`.
237
+ this.unsubscribeTokens = this.oxyServices.onTokensChanged(() => {
238
+ this.reconcileAuth();
239
+ });
240
+ // Initial projection is device-only. `refresh()` fetches the graph IFF a
241
+ // bearer is already planted (warm start); when signed out (cold boot before
242
+ // restore) it re-projects from device state and makes NO private call.
243
+ void this.refresh();
244
+ // Eager, cached Commons-availability probe (native only — a no-op when no
245
+ // `canOpenApp` was injected). It's a cheap local OS check, so by the time a
246
+ // user actually opens the sign-in entry it has almost always resolved —
247
+ // `showQr`'s own lazy probe below is only the safety net for the rare race.
248
+ void this.resolveCommonsAvailability();
249
+ }
250
+ /**
251
+ * Stop driving the dialog: unsubscribe from `SessionClient` and tear down the
252
+ * active sign-in flow (timers). Idempotent.
253
+ */
254
+ destroy() {
255
+ this.started = false;
256
+ if (this.unsubscribeSession) {
257
+ this.unsubscribeSession();
258
+ this.unsubscribeSession = null;
259
+ }
260
+ if (this.unsubscribeTokens) {
261
+ this.unsubscribeTokens();
262
+ this.unsubscribeTokens = null;
263
+ }
264
+ this.clearPollTimer();
265
+ this.closeAuthSessionSocket();
266
+ this.closeActivePopup();
267
+ this.signInToken = null;
268
+ this.listeners.clear();
269
+ }
270
+ // =========================================================================
271
+ // Auth readiness (SDK-canonical — mirrors OxyContext.canUsePrivateApi)
272
+ // =========================================================================
273
+ /**
274
+ * Whether a PRIVATE endpoint may be called right now. Mirrors the
275
+ * `hasAccessToken` term of `OxyContext.canUsePrivateApi`
276
+ * (`authResolved && isAuthenticated && tokenReady && hasAccessToken`, where
277
+ * `hasAccessToken = Boolean(oxyServices.getAccessToken())`): a planted bearer
278
+ * is the only term that decides whether a request carries auth — the other
279
+ * three are provider render-lifecycle gates with no headless equivalent.
280
+ *
281
+ * `listAccounts()` (`GET /accounts`) and `getUsersByIds()`
282
+ * (`POST /users/by-ids`) are private; calling either before cold-boot restore
283
+ * plants the token 401s → `HttpService` clears the bearer + emits
284
+ * `onTokensChanged(null)` → the app signs out. Every graph/profile fetch gates
285
+ * on this.
286
+ */
287
+ isAuthenticated() {
288
+ return Boolean(this.oxyServices.getAccessToken());
289
+ }
290
+ /**
291
+ * Reconcile the account graph against the current auth-readiness edge. On the
292
+ * signed-out → signed-in edge fetch the graph ONCE; on signed-in → signed-out
293
+ * drop it and re-project device-only. A no-op when readiness is unchanged, so
294
+ * a burst of token events / device pushes cannot restart the fetch — and a
295
+ * failed `listAccounts()` never flips the edge, so it cannot re-trigger itself
296
+ * (no retry storm).
297
+ */
298
+ reconcileAuth() {
299
+ const authed = this.isAuthenticated();
300
+ if (authed === this.authed)
301
+ return;
302
+ this.authed = authed;
303
+ if (authed) {
304
+ void this.refresh();
305
+ return;
306
+ }
307
+ // Signed out. The directory is bearer-read and `SessionClient` drops the one
308
+ // it holds when the device empties, so there is nothing to clear here — only
309
+ // the in-flight bookkeeping, which no longer describes anything.
310
+ this.error = null;
311
+ this.loading = false;
312
+ this.emit();
313
+ }
314
+ // =========================================================================
315
+ // View actions
316
+ // =========================================================================
317
+ /** Set the dialog view directly. */
318
+ setView(view) {
319
+ if (this.view === view)
320
+ return;
321
+ this.view = view;
322
+ // A `'completed'` flow owns no timers, socket, popup, or token — it is only
323
+ // the terminal "Identity confirmed" the finished surface showed. Moving to
324
+ // another view is a NEW intention, so drop it; otherwise a later `add()`
325
+ // would open on the previous sign-in's terminal state.
326
+ if (this.signIn.phase === 'completed') {
327
+ this.signIn = IDLE_SIGN_IN;
328
+ }
329
+ this.emit();
330
+ }
331
+ /** Switch to the "add account" view (the sign-in entry chooser). */
332
+ add() {
333
+ this.setView('add');
334
+ }
335
+ /** Switch to the "create account" view (passkey / Commons signup entry). */
336
+ startSignup() {
337
+ this.setView('signup');
338
+ }
339
+ // =========================================================================
340
+ // The directory
341
+ // =========================================================================
342
+ /**
343
+ * Re-read `GET /session/device/directory`. Safe to call repeatedly;
344
+ * concurrent calls are reconciled by a sequence guard so a slow earlier read
345
+ * never overwrites a newer result.
346
+ *
347
+ * This is ONE request. It used to be three — the directory, plus
348
+ * `listAccounts()` and `getUsersByIds()` to rebuild the same tree client-side
349
+ * — and the reconstruction was not merely redundant: it enumerated the
350
+ * CALLER's account graph, which on a device holding two people is one
351
+ * person's answer presented as the device's.
352
+ */
353
+ async refresh() {
354
+ const seq = ++this.refreshSeq;
355
+ // Never read the directory while signed out: at cold boot the bearer is not
356
+ // planted yet, so the call 401s → `HttpService` clears the token and signs
357
+ // the user out.
358
+ if (!this.isAuthenticated()) {
359
+ this.loading = false;
360
+ this.error = null;
361
+ this.emit();
362
+ return;
363
+ }
364
+ // Nothing to show yet is the only state worth a spinner; a re-read behind an
365
+ // already-rendered directory refreshes in place.
366
+ this.loading = this.sessionClient.getDirectory() === null;
367
+ this.error = null;
368
+ this.emit();
369
+ try {
370
+ await this.sessionClient.refreshDirectory();
371
+ }
372
+ catch (error) {
373
+ // A 401 is the EXPECTED signed-out edge, not a failure: the bearer was
374
+ // stale/revoked, so `HttpService` already cleared it and emitted
375
+ // `onTokensChanged(null)`. Any OTHER error (network, 5xx, malformed) IS
376
+ // unexpected — surface it, and keep whatever directory is already held so
377
+ // an outage degrades rather than blanks the switcher.
378
+ if ((0, errorUtils_1.extractErrorStatus)(error) === 401) {
379
+ logger_1.logger.debug('[AccountDialogController] directory unauthorized (signed out)', { component: 'AccountDialogController' }, error);
380
+ }
381
+ else {
382
+ this.error = errorMessage(error);
383
+ logger_1.logger.warn('[AccountDialogController] directory refresh failed', { component: 'AccountDialogController' }, error);
384
+ }
385
+ }
386
+ if (seq !== this.refreshSeq)
387
+ return; // superseded by a newer refresh
388
+ this.loading = false;
389
+ this.emit();
390
+ }
391
+ // =========================================================================
392
+ // Activation and the two removals (ADR 0002)
393
+ // =========================================================================
394
+ /**
395
+ * Activate one `principal acting as account` context — the ADR 0002 switch,
396
+ * and the one that can express what an account id cannot: WHICH person's
397
+ * route to a shared organization to become.
398
+ *
399
+ * There is no on-device/graph fork. The directory has a row for a context the
400
+ * principal may act as but has never entered, and `POST /session/device/
401
+ * activate` reuses or mints the delegated session server-side, so one call
402
+ * covers both cases.
403
+ *
404
+ * A context id is not stable across a removal, so a stale one is an ordinary
405
+ * outcome rather than a bug: the server answers 404 or 403, heals the row, and
406
+ * the refresh below re-reads a directory that no longer offers it.
407
+ */
408
+ async activateContext(contextId) {
409
+ if (this.activatingContextId)
410
+ return false;
411
+ this.activatingContextId = contextId;
412
+ this.error = null;
413
+ this.emit();
414
+ try {
415
+ await this.sessionClient.activateContext(contextId);
416
+ await this.refresh();
417
+ return true;
418
+ }
419
+ catch (error) {
420
+ this.error = errorMessage(error);
421
+ return false;
422
+ }
423
+ finally {
424
+ this.activatingContextId = null;
425
+ this.emit();
426
+ }
427
+ }
428
+ /**
429
+ * Remove ONE `principal → account` pair, and only that pair.
430
+ *
431
+ * Not the account across the device: the same organization reached through a
432
+ * second person is a different session with a different audit actor, and it
433
+ * stays. Routing this through `signOut({accountId})` would revoke that second
434
+ * person's access as a side effect of one person tidying their own list.
435
+ *
436
+ * The removed pair is not gone for good while the membership lives — the
437
+ * server offers it again on the next read, under a NEW id and at an unchanged
438
+ * revision — so nothing may hold a context id across this call.
439
+ */
440
+ async signOutContext(contextId) {
441
+ if (this.removingContextId || this.removingPrincipalId)
442
+ return false;
443
+ this.removingContextId = contextId;
444
+ this.error = null;
445
+ this.emit();
446
+ try {
447
+ await this.sessionClient.signOutContext(contextId);
448
+ await this.refresh();
449
+ return true;
450
+ }
451
+ catch (error) {
452
+ this.error = errorMessage(error);
453
+ return false;
454
+ }
455
+ finally {
456
+ this.removingContextId = null;
457
+ this.emit();
458
+ }
459
+ }
460
+ /**
461
+ * Remove ONE PERSON and every context they reach — and nobody else's,
462
+ * including when another principal independently operates the same account.
463
+ *
464
+ * A separate call from {@link signOutContext} because it is a separate
465
+ * question, not a loop over the first one: the server removes the principal
466
+ * and elects a replacement active context in one transition.
467
+ */
468
+ async signOutPrincipal(principalId) {
469
+ if (this.removingContextId || this.removingPrincipalId)
470
+ return false;
471
+ this.removingPrincipalId = principalId;
472
+ this.error = null;
473
+ this.emit();
474
+ try {
475
+ await this.sessionClient.signOutPrincipal(principalId);
476
+ await this.refresh();
477
+ return true;
478
+ }
479
+ catch (error) {
480
+ this.error = errorMessage(error);
481
+ return false;
482
+ }
483
+ finally {
484
+ this.removingPrincipalId = null;
485
+ this.emit();
486
+ }
487
+ }
488
+ // =========================================================================
489
+ // Sign in with Oxy (device flow — shared keychain, else cross-device QR)
490
+ // =========================================================================
491
+ /**
492
+ * Start "Sign in with Oxy". Native devices with a shared identity mint a
493
+ * session silently (`signInWithSharedIdentity`); everything else (web, or a
494
+ * native device without a shared identity) falls through to the cross-device
495
+ * QR handoff.
496
+ */
497
+ async signInWithOxy() {
498
+ this.setView('qr');
499
+ this.setSignIn({ ...IDLE_SIGN_IN_FACTS, phase: 'starting' });
500
+ try {
501
+ const session = await this.oxyServices.signInWithSharedIdentity();
502
+ if (session) {
503
+ await this.completeSignIn(session, session.user);
504
+ return;
505
+ }
506
+ }
507
+ catch (error) {
508
+ // Shared-key mint failed — log and fall through to the QR handoff rather
509
+ // than dead-ending the sign-in.
510
+ logger_1.logger.warn('[AccountDialogController] signInWithSharedIdentity failed', { component: 'AccountDialogController' }, error);
511
+ }
512
+ await this.showQr();
513
+ }
514
+ /**
515
+ * Begin (or restart) the cross-device QR handoff: create a device-flow
516
+ * session, surface its `authorizeCode` + `qrPayload`, and poll for approval.
517
+ * On approval the secret token is exchanged (`claimSessionByToken`) and the
518
+ * session committed. Requires `clientId`.
519
+ */
520
+ async showQr() {
521
+ this.cancelSignIn();
522
+ this.setView('qr');
523
+ await this.startDeviceFlowSession({ deliver: true });
524
+ }
525
+ /**
526
+ * Web-only: "Sign in with a passkey" on a non-Oxy origin cannot run the
527
+ * WebAuthn ceremony locally — a credential minted with `WEBAUTHN_RP_ID=oxy.so`
528
+ * can only be asserted from `oxy.so`/a subdomain/loopback, a browser-enforced
529
+ * boundary `isOxyRpOrigin()` (consumer-side) already gates on. Instead, open
530
+ * a popup at the auth.oxy.so passkey hub, scoped to the SAME device-flow
531
+ * session {@link showQr} would create (same `authorizeCode`/`sessionToken`
532
+ * pair), and let the SAME poll/socket/claim engine complete it once the hub
533
+ * authorizes the session (`POST /auth/session/authorize-code/:authorizeCode`,
534
+ * bearer-authed, server-side — this method never sees or transmits the
535
+ * secret `sessionToken`).
536
+ *
537
+ * The popup MUST be opened synchronously, before any `await`, or the
538
+ * browser's popup blocker loses the click-gesture attribution and silently
539
+ * blocks it — so {@link openPopup} is invoked as the very first step, before
540
+ * the device-flow session (which needs an async call) even exists. If the
541
+ * popup is blocked (or no `openPopup` was injected), this falls back to
542
+ * `showQr`'s plain QR rendering — no dead end.
543
+ */
544
+ async startPasskeyHubSignIn() {
545
+ this.cancelSignIn();
546
+ this.setView('qr');
547
+ const popup = this.openPopup?.() ?? null;
548
+ if (!popup) {
549
+ await this.startDeviceFlowSession({ deliver: true });
550
+ return;
551
+ }
552
+ // The hub popup IS the primary surface here, chosen explicitly by the user —
553
+ // so this flow does NOT run automatic Commons delivery (ringing the user's
554
+ // phone because they asked for a passkey would be exactly the "menu of
555
+ // methods" the one-primary-action rule forbids). The underlying request is
556
+ // the same `AuthSession`, and its Commons route stays the QR the view
557
+ // renders beneath the popup.
558
+ const handle = await this.startDeviceFlowSession({ deliver: false });
559
+ if (!handle) {
560
+ popup.close();
561
+ return;
562
+ }
563
+ // The user may have closed the popup during the async session creation
564
+ // above, before any watcher was attached to catch it — guard rather than
565
+ // navigate a dead window (browsers vary on whether that throws).
566
+ if (popup.closed) {
567
+ this.failSignIn('Sign-in was cancelled.');
568
+ return;
569
+ }
570
+ this.activePopup = popup;
571
+ popup.location.href = `${this.hubBaseUrl}/hub-passkey?code=${encodeURIComponent(handle.authorizeCode)}`;
572
+ this.watchPopup(popup);
573
+ }
574
+ /**
575
+ * Shared device-flow session creation for both {@link showQr} (renders the
576
+ * QR) and {@link startPasskeyHubSignIn} (also opens the hub popup) — the
577
+ * same `startCommonsSignIn` → poll/socket wiring either way. Returns the
578
+ * handle on success (already reflected in `signIn`), or `null` on failure
579
+ * (already set as `signIn.error`).
580
+ *
581
+ * @param opts.deliver - Whether to run automatic Commons delivery selection
582
+ * ({@link resolveDeliveryRoute}). `true` for the normal one-primary-action
583
+ * entry; `false` when the caller already owns the primary surface (the
584
+ * passkey hub popup), where the request's Commons route is simply the QR.
585
+ */
586
+ async startDeviceFlowSession(opts) {
587
+ if (!this.clientId) {
588
+ this.setSignIn({ ...IDLE_SIGN_IN_FACTS, phase: 'error', error: 'This app is not configured for sign-in (missing clientId).' });
589
+ return null;
590
+ }
591
+ this.setSignIn({ ...IDLE_SIGN_IN_FACTS, phase: 'starting' });
592
+ try {
593
+ const handle = await this.oxyServices.startCommonsSignIn({ clientId: this.clientId });
594
+ this.signInToken = handle.sessionToken;
595
+ this.setSignIn({
596
+ ...IDLE_SIGN_IN_FACTS,
597
+ phase: 'waiting',
598
+ authorizeCode: handle.authorizeCode,
599
+ qrPayload: handle.qrPayload,
600
+ expiresAt: handle.expiresAt,
601
+ // No route yet: the surface shows "Preparing request" until the primary
602
+ // route is resolved below. It is never guessed in the meantime.
603
+ route: opts.deliver ? null : 'qr',
604
+ });
605
+ // Primary path: an instant `auth_update` wake over the `/auth-session`
606
+ // socket. The poll below is only the fallback for when the socket can't
607
+ // connect, so it now runs at the slow fallback cadence.
608
+ this.openAuthSessionSocket(handle.sessionToken);
609
+ this.scheduleNextPoll(handle.sessionToken);
610
+ if (opts.deliver) {
611
+ // Non-blocking on purpose: the QR/authorizeCode are already renderable
612
+ // and the popup caller can navigate immediately, while the route (a
613
+ // local probe plus at most one delivery round-trip) resolves behind it.
614
+ void this.resolveDeliveryRoute(handle);
615
+ }
616
+ return handle;
617
+ }
618
+ catch (error) {
619
+ this.setSignIn({ ...IDLE_SIGN_IN_FACTS, phase: 'error', error: errorMessage(error) });
620
+ return null;
621
+ }
622
+ }
623
+ /**
624
+ * Choose and carry out the ONE primary delivery route for the active request
625
+ * (issue #691, "Automatic delivery selection").
626
+ *
627
+ * The controller gathers the facts — is a verified Commons link openable on
628
+ * THIS device, and how many known Commons installations did Oxy actually push
629
+ * to — and hands them to the pure {@link selectCommonsDelivery}. The selector
630
+ * owns the decision; this method owns only the observations and the single
631
+ * action the chosen route implies. It never cascades: a route that yields
632
+ * nothing resolves to QR *before* a route is chosen, never after.
633
+ */
634
+ async resolveDeliveryRoute(handle) {
635
+ if (!this.isAwaitingApproval(handle.sessionToken))
636
+ return;
637
+ // Fact 1 — a VERIFIED Commons link openable on this very device. Native
638
+ // only; on web `commonsAvailability` stays `'unknown'` (a browser cannot be
639
+ // asked whether a custom scheme is registered) and this is simply `false`.
640
+ if (this.canOpenApp &&
641
+ (this.commonsAvailability === 'unknown' || this.commonsAvailability === 'checking')) {
642
+ await this.resolveCommonsAvailability();
643
+ if (!this.isAwaitingApproval(handle.sessionToken))
644
+ return;
645
+ }
646
+ const commonsAvailable = this.commonsAvailability === 'available';
647
+ // Fact 2 — how many known Commons installations the server pushed to.
648
+ const pushTargets = await this.deliverToKnownCommons(handle.authorizeCode, commonsAvailable);
649
+ if (!this.isAwaitingApproval(handle.sessionToken))
650
+ return;
651
+ const route = (0, commonsDelivery_1.selectCommonsDelivery)({ platform: this.platform, commonsAvailable, pushTargets });
652
+ // The only route that has an action to perform on this device — and the only
653
+ // one that can fail here. `'await-push'` was already dispatched server-side;
654
+ // `'qr'` is rendered by the surface from `qrPayload`.
655
+ const routeFailed = route === 'open-commons' ? !this.openCommonsLink(handle.qrPayload) : false;
656
+ this.patchSignIn({ route, routeFailed });
657
+ }
658
+ /**
659
+ * Whether `sessionToken` is still THE request this surface is waiting on.
660
+ *
661
+ * Guards every step of the asynchronous route resolution: a cancelled,
662
+ * superseded, failed, or already-approved flow must neither open Commons nor
663
+ * mutate the surface — an approval that lands mid-resolution would otherwise
664
+ * be followed by a pointless app switch.
665
+ */
666
+ isAwaitingApproval(sessionToken) {
667
+ return this.signInToken === sessionToken && this.signIn.phase === 'waiting';
668
+ }
669
+ /**
670
+ * Ask Oxy to deliver the pending request to the identity's known Commons
671
+ * installations, returning how many it reached (`0` when delivery is not
672
+ * applicable, not permitted, or reached nobody).
673
+ *
674
+ * Two hard rules, both from the issue:
675
+ * - **Never push from an unauthenticated surface.** `deliverCommonsSignIn`
676
+ * is bearer-required precisely because a request that merely carries a
677
+ * typed-in username must never be able to ring somebody's phone. Without a
678
+ * planted bearer the call is not made AT ALL — not made-and-failed.
679
+ * - **Zero targets and a failed delivery are the same normal outcome.** Both
680
+ * return `0`, which resolves the primary route to QR silently. Neither is
681
+ * surfaced as an error: there is nothing the user did wrong and nothing for
682
+ * them to fix.
683
+ */
684
+ async deliverToKnownCommons(authorizeCode, commonsAvailable) {
685
+ // Route 1 (mobile with a verified local Commons link) reaches the identity
686
+ // on this very device — pushing as well would notify a second surface for a
687
+ // request the user is about to confirm here.
688
+ if (this.platform === 'mobile' && commonsAvailable)
689
+ return 0;
690
+ if (!this.isAuthenticated())
691
+ return 0;
692
+ try {
693
+ const result = await this.oxyServices.deliverCommonsSignIn(authorizeCode);
694
+ // `delivered: false` with `targets > 0` is a transport failure, not a
695
+ // reachable install — the shared helper owns that rule so the surface
696
+ // can never park a user on "check your phone" for a push that failed.
697
+ return (0, commonsDelivery_1.pushTargetsFromDelivery)(result);
698
+ }
699
+ catch (error) {
700
+ logger_1.logger.debug('[AccountDialogController] Commons delivery unavailable (QR route)', { component: 'AccountDialogController' }, error);
701
+ return 0;
702
+ }
703
+ }
704
+ /**
705
+ * Open the verified Commons link for the `'open-commons'` route. Returns
706
+ * whether the navigation was actually handed off, so a missing opener or a
707
+ * throwing one becomes an observable `routeFailed` instead of a silent dead
708
+ * end the user stares at.
709
+ */
710
+ openCommonsLink(qrPayload) {
711
+ if (!this.openUrl)
712
+ return false;
713
+ try {
714
+ this.openUrl(qrPayload);
715
+ return true;
716
+ }
717
+ catch (error) {
718
+ logger_1.logger.debug('[AccountDialogController] Commons deep link failed', { component: 'AccountDialogController' }, error);
719
+ return false;
720
+ }
721
+ }
722
+ /**
723
+ * Poll {@link PopupWindowHandle.closed} so a user who dismisses the hub
724
+ * popup without completing sign-in gets prompt feedback (there is no DOM
725
+ * event for a cross-origin popup closing — polling is the only mechanism).
726
+ * Cleared by {@link closeActivePopup}, which every sign-in exit path already
727
+ * calls.
728
+ */
729
+ watchPopup(popup) {
730
+ this.clearPopupWatchTimer();
731
+ this.popupWatchTimer = setInterval(() => {
732
+ if (!popup.closed)
733
+ return;
734
+ this.clearPopupWatchTimer();
735
+ if (this.signIn.phase === 'starting' || this.signIn.phase === 'waiting') {
736
+ // Closing the surface cancels the REQUEST too, not just this listener.
737
+ const pendingCode = this.signIn.authorizeCode;
738
+ this.failSignIn('Sign-in was cancelled.');
739
+ if (pendingCode) {
740
+ void this.withdrawRequest(pendingCode);
741
+ }
742
+ }
743
+ }, 1000);
744
+ }
745
+ clearPopupWatchTimer() {
746
+ if (this.popupWatchTimer !== null) {
747
+ clearInterval(this.popupWatchTimer);
748
+ this.popupWatchTimer = null;
749
+ }
750
+ }
751
+ /** Tear down the popup watch timer and close the popup, if any. Idempotent. */
752
+ closeActivePopup() {
753
+ this.clearPopupWatchTimer();
754
+ const popup = this.activePopup;
755
+ this.activePopup = null;
756
+ if (!popup || popup.closed)
757
+ return;
758
+ try {
759
+ popup.close();
760
+ }
761
+ catch (error) {
762
+ logger_1.logger.debug('[AccountDialogController] popup close failed', { component: 'AccountDialogController' }, error);
763
+ }
764
+ }
765
+ /**
766
+ * Resolve whether Commons is installed on this device via the injected
767
+ * `canOpenApp` probe, updating {@link commonsAvailability} as durable,
768
+ * observable snapshot state. Native only — a no-op when `canOpenApp` was
769
+ * not injected (web), where `commonsAvailability` stays `'unknown'` forever
770
+ * and the QR view renders unconditionally (no gating).
771
+ *
772
+ * Replaces the old `maybeOpenCommons` fire-and-forget probe, whose outcome
773
+ * was only ever reflected by whether Commons silently opened — a probe
774
+ * failure or "not installed" answer was swallowed into a debug log with no
775
+ * way for the UI to react. `commonsAvailability` fixes that.
776
+ */
777
+ async resolveCommonsAvailability() {
778
+ if (!this.canOpenApp)
779
+ return;
780
+ this.commonsAvailability = 'checking';
781
+ this.emit();
782
+ let available = false;
783
+ try {
784
+ available = await this.canOpenApp(COMMONS_APP_SCHEME);
785
+ }
786
+ catch (error) {
787
+ logger_1.logger.debug('[AccountDialogController] Commons availability probe failed', { component: 'AccountDialogController' }, error);
788
+ available = false; // fail-closed — treat a probe error as "not installed"
789
+ }
790
+ this.commonsAvailability = available ? 'available' : 'unavailable';
791
+ this.emit();
792
+ }
793
+ /**
794
+ * Tear down the active sign-in device flow (timers + socket + popup + token),
795
+ * WITHDRAW the request server-side, and reset to idle.
796
+ *
797
+ * Cancellation has to converge in both directions: the surface closing must
798
+ * cancel the request, not just stop listening to it. Without the withdrawal a
799
+ * dismissed QR would stay approvable until it expired, so a later scan of a
800
+ * stale code could authorize a session nobody is waiting for.
801
+ */
802
+ cancelSignIn() {
803
+ // Capture before the teardown clears it, and only for a request that can
804
+ // still be approved — a completed/failed flow has nothing to withdraw.
805
+ const pendingCode = this.signIn.phase === 'starting' || this.signIn.phase === 'waiting'
806
+ ? this.signIn.authorizeCode
807
+ : null;
808
+ this.clearPollTimer();
809
+ this.closeAuthSessionSocket();
810
+ this.closeActivePopup();
811
+ this.signInToken = null;
812
+ if (this.signIn !== IDLE_SIGN_IN) {
813
+ this.setSignIn(IDLE_SIGN_IN_FACTS);
814
+ }
815
+ if (pendingCode) {
816
+ void this.withdrawRequest(pendingCode);
817
+ }
818
+ }
819
+ /**
820
+ * Best-effort server-side withdrawal of a request this surface abandoned
821
+ * (`POST /auth/session/deny/:authorizeCode`). Fire-and-forget by design: the
822
+ * local teardown already happened, and a race with an approval that just
823
+ * landed legitimately rejects here — neither outcome is worth surfacing.
824
+ */
825
+ async withdrawRequest(authorizeCode) {
826
+ try {
827
+ await this.oxyServices.denyCommonsSignIn(authorizeCode);
828
+ }
829
+ catch (error) {
830
+ logger_1.logger.debug('[AccountDialogController] request withdrawal failed', { component: 'AccountDialogController' }, error);
831
+ }
832
+ }
833
+ // =========================================================================
834
+ // Internal sign-in helpers
835
+ // =========================================================================
836
+ scheduleNextPoll(sessionToken) {
837
+ this.clearPollTimer();
838
+ this.pollTimer = setTimeout(() => {
839
+ void this.pollOnce(sessionToken);
840
+ }, this.pollIntervalMs);
841
+ }
842
+ /**
843
+ * Run one status check + (on approval) claim. Triggered by the fallback timer
844
+ * AND by the `/auth-session` socket's `auth_update` wake, so it is guarded
845
+ * against concurrent entry: whichever fires first claims the single-use token;
846
+ * the other no-ops. The `auth_update` payload is never trusted — this always
847
+ * re-checks the authoritative status via `pollCommonsSignIn`.
848
+ */
849
+ async pollOnce(sessionToken) {
850
+ // A superseded / cancelled flow must not act; a poll already running owns the claim.
851
+ if (this.signInToken !== sessionToken || this.pollInFlight)
852
+ return;
853
+ this.pollInFlight = true;
854
+ try {
855
+ const expiresAt = this.signIn.expiresAt;
856
+ if (typeof expiresAt === 'number' && Date.now() > expiresAt) {
857
+ this.failSignIn('Session expired. Please try again.');
858
+ return;
859
+ }
860
+ try {
861
+ const status = await this.oxyServices.pollCommonsSignIn(sessionToken);
862
+ if (this.signInToken !== sessionToken)
863
+ return; // cancelled mid-request
864
+ // Delivery PROGRESS first: it is reported alongside every status, and
865
+ // recording it before the terminal branches means a poll that also
866
+ // carries the approval still leaves an honest trail behind it.
867
+ this.recordDeliveryProgress(status.pushSentAt, status.openedAt);
868
+ const purpose = status.purpose === 'oauth_authorization' ? 'oauth_authorization' : 'device_sign_in';
869
+ if (status.authorized && purpose === 'oauth_authorization') {
870
+ // OAuth-bound sessions mint no sessionId on approval — they finalize
871
+ // into an authorization code. The account dialog only starts device
872
+ // sign-in today; stop rather than poll until expiry.
873
+ this.failSignIn('This sign-in flow cannot be completed here. Use the app\'s OAuth sign-in instead.');
874
+ return;
875
+ }
876
+ if (status.authorized && status.sessionId) {
877
+ this.clearPollTimer();
878
+ await this.claimAndComplete(status.sessionId, sessionToken);
879
+ return;
880
+ }
881
+ if (status.status === 'cancelled') {
882
+ this.failSignIn('Authorization was denied.');
883
+ return;
884
+ }
885
+ if (status.status === 'expired') {
886
+ this.failSignIn('Session expired. Please try again.');
887
+ return;
888
+ }
889
+ }
890
+ catch (error) {
891
+ // Transient poll error — the next tick retries. Logged, never thrown.
892
+ logger_1.logger.debug('[AccountDialogController] poll error (will retry)', { component: 'AccountDialogController' }, error);
893
+ }
894
+ if (this.signInToken === sessionToken) {
895
+ this.scheduleNextPoll(sessionToken);
896
+ }
897
+ }
898
+ finally {
899
+ this.pollInFlight = false;
900
+ }
901
+ }
902
+ /**
903
+ * Record server-reported delivery progress on the active flow.
904
+ *
905
+ * Monotone and additive: a timestamp is only ever adopted, never replaced or
906
+ * cleared, so an older API build (or a partial payload) that omits a field can
907
+ * at most fail to advance the surface — it can never walk it backwards.
908
+ * Emits only on a real change, so a steady poll does not churn the snapshot.
909
+ */
910
+ recordDeliveryProgress(pushSentAt, openedAt) {
911
+ const nextPushSentAt = this.signIn.pushSentAt ?? pushSentAt ?? null;
912
+ const nextOpenedAt = this.signIn.openedAt ?? openedAt ?? null;
913
+ if (nextPushSentAt === this.signIn.pushSentAt && nextOpenedAt === this.signIn.openedAt)
914
+ return;
915
+ this.patchSignIn({ pushSentAt: nextPushSentAt, openedAt: nextOpenedAt });
916
+ }
917
+ async claimAndComplete(sessionId, sessionToken) {
918
+ this.patchSignIn({ phase: 'authorized' });
919
+ let claimed;
920
+ try {
921
+ claimed = await this.oxyServices.claimSessionByToken(sessionToken);
922
+ }
923
+ catch (error) {
924
+ this.failSignIn(errorMessage(error));
925
+ return;
926
+ }
927
+ if (!claimed?.accessToken || !claimed.user) {
928
+ this.failSignIn('Authorization succeeded but the session could not be claimed. Please try again.');
929
+ return;
930
+ }
931
+ // `SessionLoginResponse.user` is the minimal session-carried shape; the claim
932
+ // returns the full `User` (avatar is `string | null | undefined`). Normalize
933
+ // rather than widening the minimal shape to accept `null`.
934
+ const minimalUser = {
935
+ id: claimed.user.id,
936
+ username: claimed.user.username,
937
+ name: claimed.user.name,
938
+ avatar: claimed.user.avatar ?? undefined,
939
+ };
940
+ try {
941
+ await this.completeSignIn({
942
+ sessionId: claimed.sessionId || sessionId,
943
+ deviceId: claimed.deviceId ?? '',
944
+ expiresAt: claimed.expiresAt ?? '',
945
+ user: minimalUser,
946
+ accessToken: claimed.accessToken,
947
+ ...(claimed.deviceSecret ? { deviceSecret: claimed.deviceSecret } : {}),
948
+ }, minimalUser);
949
+ }
950
+ catch (error) {
951
+ this.failSignIn(errorMessage(error));
952
+ }
953
+ }
954
+ /**
955
+ * Commit an authorized session, notify, and return to the account list. Shared
956
+ * by the shared-key, QR, and mint-switch paths so they cannot drift.
957
+ */
958
+ async completeSignIn(session, user) {
959
+ await this.commitAuthorizedSession(session, user);
960
+ this.signInToken = null;
961
+ this.clearPollTimer();
962
+ this.closeAuthSessionSocket();
963
+ this.closeActivePopup();
964
+ // Terminal SUCCESS, not idle: the surface gets one honest frame to show
965
+ // "Identity confirmed" before it closes. Cleared on the next view change.
966
+ this.signIn = COMPLETED_SIGN_IN;
967
+ this.view = 'accounts';
968
+ this.emit();
969
+ this.onSignedIn?.(user);
970
+ await this.refresh();
971
+ }
972
+ /**
973
+ * Register a token-planted session into the device set. Prefers the
974
+ * consumer's commit funnel (durable persist + hydration); falls back to
975
+ * `SessionClient.registerAndActivate` (registration + activation only).
976
+ */
977
+ async commitAuthorizedSession(session, user) {
978
+ if (this.commitSession) {
979
+ await this.commitSession(session);
980
+ }
981
+ else {
982
+ await this.sessionClient.registerAndActivate(user.id);
983
+ }
984
+ }
985
+ failSignIn(message) {
986
+ this.clearPollTimer();
987
+ this.closeAuthSessionSocket();
988
+ this.closeActivePopup();
989
+ this.signInToken = null;
990
+ this.setSignIn({ ...IDLE_SIGN_IN_FACTS, phase: 'error', error: message });
991
+ }
992
+ clearPollTimer() {
993
+ if (this.pollTimer !== null) {
994
+ clearTimeout(this.pollTimer);
995
+ this.pollTimer = null;
996
+ }
997
+ }
998
+ // =========================================================================
999
+ // /auth-session socket (instant QR approval wake — replaces 3s polling)
1000
+ // =========================================================================
1001
+ /**
1002
+ * Subscribe the active QR flow to the `/auth-session` namespace so the API's
1003
+ * `auth_update` event wakes {@link pollOnce} the instant the approval lands.
1004
+ *
1005
+ * The join is keyed by the secret `sessionToken` (the server's `auth:<token>`
1006
+ * room, joined by emitting `join`) and re-issued on every (re)connect so it
1007
+ * survives socket drops. `auth_update` is treated as a pure SIGNAL — the payload
1008
+ * is never trusted; `pollOnce` re-checks the authoritative status and claims.
1009
+ *
1010
+ * No-op (poll-only) when the optional socket transport is unavailable. The
1011
+ * namespace needs no auth.
1012
+ */
1013
+ async openAuthSessionSocket(sessionToken) {
1014
+ this.closeAuthSessionSocket();
1015
+ const socketFactory = this.socketFactory ?? (await (0, socketLoader_1.getSocketIO)());
1016
+ if (!socketFactory || this.signInToken !== sessionToken)
1017
+ return;
1018
+ let socket;
1019
+ try {
1020
+ socket = socketFactory(`${this.oxyServices.getBaseURL()}${AUTH_SESSION_NAMESPACE}`, {
1021
+ transports: ['websocket'],
1022
+ autoConnect: true,
1023
+ reconnection: true,
1024
+ reconnectionAttempts: Number.POSITIVE_INFINITY,
1025
+ reconnectionDelay: 1000,
1026
+ reconnectionDelayMax: 10000,
1027
+ });
1028
+ }
1029
+ catch (error) {
1030
+ // Socket unavailable — the fallback poll still completes the flow.
1031
+ logger_1.logger.debug('[AccountDialogController] auth-session socket create failed (poll fallback)', { component: 'AccountDialogController' }, error);
1032
+ return;
1033
+ }
1034
+ const join = () => {
1035
+ if (this.signInToken !== sessionToken)
1036
+ return;
1037
+ try {
1038
+ socket.emit('join', sessionToken);
1039
+ }
1040
+ catch (error) {
1041
+ logger_1.logger.debug('[AccountDialogController] auth-session join failed', { component: 'AccountDialogController' }, error);
1042
+ }
1043
+ };
1044
+ socket.on('connect', join);
1045
+ if (socket.connected)
1046
+ join();
1047
+ socket.on('auth_update', () => {
1048
+ if (this.signInToken !== sessionToken)
1049
+ return;
1050
+ // Pure wake signal — re-check the authoritative status + claim the poll would have.
1051
+ void this.pollOnce(sessionToken);
1052
+ });
1053
+ this.authSessionSocket = socket;
1054
+ }
1055
+ /** Tear down the `/auth-session` socket, if any. Idempotent. */
1056
+ closeAuthSessionSocket() {
1057
+ const socket = this.authSessionSocket;
1058
+ if (!socket)
1059
+ return;
1060
+ this.authSessionSocket = null;
1061
+ try {
1062
+ socket.off('auth_update');
1063
+ socket.off('connect');
1064
+ socket.disconnect();
1065
+ }
1066
+ catch (error) {
1067
+ logger_1.logger.debug('[AccountDialogController] auth-session socket close failed', { component: 'AccountDialogController' }, error);
1068
+ }
1069
+ }
1070
+ // =========================================================================
1071
+ // Snapshot plumbing
1072
+ // =========================================================================
1073
+ /**
1074
+ * Replace the device-flow state from its FACTS, re-deriving `progress`. The
1075
+ * only writer of `this.signIn` besides the two terminal constants — which is
1076
+ * what keeps `progress` impossible to set by hand, and therefore impossible
1077
+ * to advance without a fact behind it.
1078
+ */
1079
+ setSignIn(facts) {
1080
+ this.signIn = { ...facts, progress: deriveSignInProgress(facts) };
1081
+ this.emit();
1082
+ }
1083
+ /** Update a subset of the device-flow facts, re-deriving `progress`. */
1084
+ patchSignIn(patch) {
1085
+ const { phase, authorizeCode, qrPayload, expiresAt, error, route, routeFailed, pushSentAt, openedAt, } = this.signIn;
1086
+ this.setSignIn({
1087
+ phase,
1088
+ authorizeCode,
1089
+ qrPayload,
1090
+ expiresAt,
1091
+ error,
1092
+ route,
1093
+ routeFailed,
1094
+ pushSentAt,
1095
+ openedAt,
1096
+ ...patch,
1097
+ });
1098
+ }
1099
+ computeSnapshot() {
1100
+ const directory = this.sessionClient.getDirectory();
1101
+ return {
1102
+ view: this.view,
1103
+ directory,
1104
+ activeContext: (0, deviceDirectory_1.resolveActiveContext)(directory),
1105
+ loading: this.loading,
1106
+ error: this.error,
1107
+ activatingContextId: this.activatingContextId,
1108
+ removingContextId: this.removingContextId,
1109
+ removingPrincipalId: this.removingPrincipalId,
1110
+ signIn: this.signIn,
1111
+ commonsAvailability: this.commonsAvailability,
1112
+ };
1113
+ }
1114
+ /** Recompute the snapshot and notify subscribers. */
1115
+ emit() {
1116
+ this.snapshot = this.computeSnapshot();
1117
+ for (const listener of this.listeners) {
1118
+ try {
1119
+ listener(this.snapshot);
1120
+ }
1121
+ catch (error) {
1122
+ logger_1.logger.error('[AccountDialogController] subscriber threw', error);
1123
+ }
1124
+ }
1125
+ }
1126
+ }
1127
+ exports.AccountDialogController = AccountDialogController;
1128
+ /** Factory mirroring `createSessionClient`, for ergonomic wiring by consumers. */
1129
+ function createAccountDialogController(options) {
1130
+ return new AccountDialogController(options);
1131
+ }