@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,1254 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceCredentialMismatchError = exports.parseCommonsApprovalExpiresAt = exports.getCommonsApprovalBlockingReason = void 0;
4
+ exports.OxyServicesAuthMixin = OxyServicesAuthMixin;
5
+ const contracts_1 = require("@oxy.so/contracts");
6
+ var commonsApproval_1 = require("../utils/commonsApproval");
7
+ Object.defineProperty(exports, "getCommonsApprovalBlockingReason", { enumerable: true, get: function () { return commonsApproval_1.getCommonsApprovalBlockingReason; } });
8
+ Object.defineProperty(exports, "parseCommonsApprovalExpiresAt", { enumerable: true, get: function () { return commonsApproval_1.parseCommonsApprovalExpiresAt; } });
9
+ const OxyServices_errors_1 = require("../OxyServices.errors");
10
+ const keyManager_1 = require("../crypto/keyManager");
11
+ const signatureService_1 = require("../crypto/signatureService");
12
+ const protocol_1 = require("@oxy.so/protocol");
13
+ const logger_1 = require("../logger");
14
+ const userIdentity_1 = require("../utils/userIdentity");
15
+ /**
16
+ * Default lifetime of a "Sign in with Oxy" device-flow session / authorize code.
17
+ * Matches the authorize-code TTL the server enforces (5 minutes). The server's
18
+ * returned `expiresAt` is authoritative; this is only the client-proposed value.
19
+ */
20
+ const COMMONS_SIGN_IN_EXPIRY_MS = 5 * 60 * 1000;
21
+ /**
22
+ * Fallback access-token lifetime used only if the token endpoint ever omits the
23
+ * RFC 6749 `expires_in` member. Matches the server's current 15-minute access
24
+ * token; the server's value always wins when present.
25
+ */
26
+ const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 15 * 60;
27
+ /**
28
+ * @internal Narrow an untrusted `requesterLabel` from the approve-info response.
29
+ *
30
+ * Returns the trimmed label only when the server sent a real, non-empty string;
31
+ * everything else — absent (an API that predates the field), `null` (a native
32
+ * requester the server could not describe), or a non-string — degrades to
33
+ * `null`, so the approval UI drops the line instead of rendering a blank or a
34
+ * coerced value under the app it is about to authorize.
35
+ */
36
+ function parseCommonsRequesterLabel(value) {
37
+ if (typeof value !== 'string') {
38
+ return null;
39
+ }
40
+ const label = value.trim();
41
+ return label.length > 0 ? label : null;
42
+ }
43
+ /**
44
+ * @internal Narrow an untrusted `subjectAccount` from the approve-info response.
45
+ *
46
+ * Returns `null` unless the value is an object carrying a non-empty string `id`
47
+ * AND `username` — the two fields the approval UI needs to name the delegated
48
+ * account. A half-populated object is rejected whole rather than rendered with
49
+ * blanks, and `displayName` is only carried through when it is a string.
50
+ */
51
+ function parseCommonsSubjectAccount(value) {
52
+ if (value === null || typeof value !== 'object') {
53
+ return null;
54
+ }
55
+ const raw = value;
56
+ const { id, username, displayName } = raw;
57
+ if (typeof id !== 'string' || !id || typeof username !== 'string' || !username) {
58
+ return null;
59
+ }
60
+ return {
61
+ id,
62
+ username,
63
+ ...(typeof displayName === 'string' ? { displayName } : {}),
64
+ };
65
+ }
66
+ /**
67
+ * @internal Narrow an untrusted delivery-progress timestamp from the status
68
+ * response.
69
+ *
70
+ * Returns the ISO-8601 string unchanged when it is a real, parseable instant,
71
+ * and `null` for everything else — absent (an older API that has no delivery
72
+ * progress at all), empty, non-string, or unparseable. Progress is advisory, so
73
+ * degrading to "no progress yet" is always safe; surfacing a garbage timestamp
74
+ * to the waiting UI is not.
75
+ */
76
+ function parseCommonsProgressTimestamp(value) {
77
+ if (typeof value !== 'string' || !value) {
78
+ return null;
79
+ }
80
+ return Number.isFinite(Date.parse(value)) ? value : null;
81
+ }
82
+ /**
83
+ * Sentinel error raised when getServiceToken() is called with a known apiKey
84
+ * but a non-matching secret. Indicates either credential drift in the caller
85
+ * or a cross-tenant cache lookup attempt. Surface as a 401-equivalent.
86
+ */
87
+ class ServiceCredentialMismatchError extends Error {
88
+ constructor() {
89
+ super('Service credential mismatch: provided secret does not match the secret stored for this apiKey');
90
+ this.name = 'ServiceCredentialMismatchError';
91
+ }
92
+ }
93
+ exports.ServiceCredentialMismatchError = ServiceCredentialMismatchError;
94
+ function OxyServicesAuthMixin(Base) {
95
+ return class extends Base {
96
+ constructor(...args) {
97
+ super(...args);
98
+ /**
99
+ * Per-credential token cache.
100
+ *
101
+ * Keyed by SHA-256(apiKey). Each entry carries:
102
+ * - the issued service JWT
103
+ * - its expiry timestamp
104
+ * - the secret that produced it (Buffer for constant-time compare)
105
+ * - an optional in-flight promise to deduplicate concurrent refreshes
106
+ *
107
+ * The previous implementation kept ONE token/exp pair per OxyServices
108
+ * instance. That meant calling `getServiceToken(keyA, secretA)` populated
109
+ * the cache, and a subsequent `getServiceToken(keyB, secretB)` (different
110
+ * tenant) would receive tenant A's token. This is fixed by routing every
111
+ * lookup through the Map.
112
+ *
113
+ * @internal
114
+ */
115
+ this._serviceTokenCache = new Map();
116
+ /** @internal Raw apiKey stored by configureServiceAuth() for use by getServiceToken() */
117
+ this._serviceApiKey = null;
118
+ /** @internal Raw apiSecret stored by configureServiceAuth() for use by getServiceToken() */
119
+ this._serviceApiSecret = null;
120
+ }
121
+ /**
122
+ * Hash an apiKey into a stable Map cache key. Uses Node's SHA-256 — service
123
+ * tokens are only ever issued by a Node host (the SDK on web/RN never has
124
+ * the apiSecret in the first place), so we can rely on Node crypto here.
125
+ *
126
+ * @internal
127
+ */
128
+ async _hashApiKey(apiKey) {
129
+ const nodeCrypto = await (0, protocol_1.loadNodeCrypto)();
130
+ return nodeCrypto.createHash('sha256').update(apiKey).digest('hex');
131
+ }
132
+ /**
133
+ * Configure service credentials for internal service-to-service communication.
134
+ * Call this once at startup so that getServiceToken() and makeServiceRequest()
135
+ * can automatically obtain and refresh tokens.
136
+ *
137
+ * Calling this with credentials that differ from a previously-configured pair
138
+ * is allowed — each `(apiKey, apiSecret)` pair is cached independently, so
139
+ * legitimate multi-tenant hosts that need to switch credentials cannot leak
140
+ * one tenant's token to another tenant on the same instance.
141
+ *
142
+ * @param apiKey - Application credential public key (oxy_dk_*)
143
+ * @param apiSecret - Application credential secret
144
+ */
145
+ configureServiceAuth(apiKey, apiSecret) {
146
+ this._serviceApiKey = apiKey;
147
+ this._serviceApiSecret = apiSecret;
148
+ }
149
+ /**
150
+ * Get a service token for internal service-to-service communication.
151
+ * Tokens are short-lived (1h) and automatically cached/refreshed per
152
+ * `(apiKey, apiSecret)` pair.
153
+ *
154
+ * Concurrent callers for the same credential pair share a single in-flight
155
+ * request to avoid hammering `/auth/service-token` when the cache is empty
156
+ * or expired.
157
+ *
158
+ * **Security guarantee:** if the cache already holds a token for this
159
+ * apiKey but the supplied apiSecret does not constant-time match the
160
+ * secret that originally produced that token, this method throws
161
+ * `ServiceCredentialMismatchError` instead of returning the cached token.
162
+ * This prevents an attacker who learned a peer's apiKey from extracting
163
+ * their service token by polling with a wrong secret.
164
+ *
165
+ * @param apiKey - Application credential public key (optional if configureServiceAuth was called)
166
+ * @param apiSecret - Application credential secret (optional if configureServiceAuth was called)
167
+ */
168
+ async getServiceToken(apiKey, apiSecret) {
169
+ const key = apiKey || this._serviceApiKey;
170
+ const secret = apiSecret || this._serviceApiSecret;
171
+ if (!key || !secret) {
172
+ throw new Error('Service credentials not provided. Call configureServiceAuth() or pass apiKey and apiSecret.');
173
+ }
174
+ const cacheKey = await this._hashApiKey(key);
175
+ const now = Date.now();
176
+ const providedSecretBuf = Buffer.from(secret, 'utf8');
177
+ let entry = this._serviceTokenCache.get(cacheKey);
178
+ // Verify the secret on every cache hit, regardless of token freshness.
179
+ // Constant-time compare prevents timing oracles on the stored secret.
180
+ if (entry) {
181
+ const nodeCrypto = await (0, protocol_1.loadNodeCrypto)();
182
+ const storedSecretBuf = entry.secretBuf;
183
+ const lengthMatch = storedSecretBuf.length === providedSecretBuf.length;
184
+ // Always run timingSafeEqual on equal-length inputs to keep timing flat.
185
+ // When lengths differ, run against a zero-padded copy of the same length
186
+ // to avoid an early-return timing signal.
187
+ const compareBuf = lengthMatch
188
+ ? providedSecretBuf
189
+ : Buffer.alloc(storedSecretBuf.length);
190
+ const compareResult = nodeCrypto.timingSafeEqual(storedSecretBuf, compareBuf);
191
+ if (!lengthMatch || !compareResult) {
192
+ logger_1.logger.warn('[oxy.auth] Service token cache hit with mismatched secret', {
193
+ component: 'auth',
194
+ method: 'getServiceToken',
195
+ });
196
+ throw new ServiceCredentialMismatchError();
197
+ }
198
+ // Return cached token if still valid (with 60s buffer for clock drift)
199
+ if (entry.token && entry.expiresAt > now + 60000) {
200
+ return entry.token;
201
+ }
202
+ // If a fetch is already in-flight for this credential, share its result
203
+ if (entry.pending) {
204
+ return entry.pending;
205
+ }
206
+ }
207
+ else {
208
+ // First time seeing this apiKey on this instance — seed an empty entry
209
+ // so concurrent callers serialize on the same promise.
210
+ entry = {
211
+ token: '',
212
+ expiresAt: 0,
213
+ secretBuf: providedSecretBuf,
214
+ pending: null,
215
+ apiKey: key,
216
+ };
217
+ this._serviceTokenCache.set(cacheKey, entry);
218
+ }
219
+ const pending = this._doFetchServiceToken(key, secret, cacheKey, providedSecretBuf);
220
+ entry.pending = pending;
221
+ try {
222
+ return await pending;
223
+ }
224
+ catch (error) {
225
+ // Do not retain unauthenticated cache entries. If the initial
226
+ // /auth/service-token request fails (for example, wrong apiSecret),
227
+ // leaving the pre-seeded empty entry would cause later calls with the
228
+ // real secret for the same apiKey to fail locally as a credential
229
+ // mismatch without ever contacting the server. Keep previously-issued
230
+ // stale tokens on refresh failures, but remove never-authenticated
231
+ // entries.
232
+ const failed = this._serviceTokenCache.get(cacheKey);
233
+ if (failed?.pending === pending && !failed.token) {
234
+ this._serviceTokenCache.delete(cacheKey);
235
+ }
236
+ throw error;
237
+ }
238
+ finally {
239
+ // Clear the in-flight slot; the entry itself (with fresh token / expiry)
240
+ // is updated inside _doFetchServiceToken before we land here.
241
+ const settled = this._serviceTokenCache.get(cacheKey);
242
+ if (settled?.pending === pending) {
243
+ settled.pending = null;
244
+ }
245
+ }
246
+ }
247
+ /**
248
+ * Perform the actual /auth/service-token request and cache the result.
249
+ * Separated so getServiceToken() can deduplicate concurrent calls.
250
+ * @internal
251
+ */
252
+ async _doFetchServiceToken(key, secret, cacheKey, secretBuf) {
253
+ const response = await this.makeRequest('POST', '/auth/service-token', { apiKey: key, apiSecret: secret }, { cache: false, retry: false, skipAuth: true });
254
+ const expiresAt = Date.now() + response.expiresIn * 1000;
255
+ // Update the entry in-place so any caller that already grabbed a reference
256
+ // (via `_serviceTokenCache.get(...)`) sees the fresh state.
257
+ const entry = this._serviceTokenCache.get(cacheKey);
258
+ if (entry) {
259
+ entry.token = response.token;
260
+ entry.expiresAt = expiresAt;
261
+ entry.secretBuf = secretBuf;
262
+ }
263
+ else {
264
+ this._serviceTokenCache.set(cacheKey, {
265
+ token: response.token,
266
+ expiresAt,
267
+ secretBuf,
268
+ pending: null,
269
+ apiKey: key,
270
+ });
271
+ }
272
+ return response.token;
273
+ }
274
+ /**
275
+ * Invalidate cached service token(s), forcing the next `getServiceToken()`
276
+ * call to mint a fresh token from `/auth/service-token`.
277
+ *
278
+ * `getServiceToken()` only refreshes on expiry (with a 60s clock-drift
279
+ * buffer), so a credential that is revoked or rotated mid-run — surfaced as
280
+ * a 401 on a downstream service request — cannot otherwise be recovered
281
+ * within the same process: the still-unexpired cached token keeps being
282
+ * returned. Call this after such a 401 to clear the stale entry; the very
283
+ * next `getServiceToken()` for that credential re-mints.
284
+ *
285
+ * Fully synchronous and deterministic: the call completes before it
286
+ * returns, so a `getServiceToken()` issued immediately afterwards is
287
+ * guaranteed to see the cleared cache and mint anew.
288
+ *
289
+ * @param apiKey - When provided, clears only the cache entry for that
290
+ * specific apiKey. When omitted, clears the entry for the credential set
291
+ * via `configureServiceAuth()`; if neither is available (no key to
292
+ * target), clears the entire cache. Passing no argument is the common
293
+ * case for hosts that configured a single service credential at startup.
294
+ *
295
+ * The cache Map is keyed by an asynchronously-computed `SHA-256(apiKey)`
296
+ * that cannot be reproduced synchronously, so a targeted clear scans the
297
+ * entries and removes the one whose stored raw `apiKey` matches — keeping
298
+ * this method synchronous. The fully-untargeted call (no argument and no
299
+ * configured key) clears every entry, which is safe because each credential
300
+ * pair is independently re-minted on its next request.
301
+ */
302
+ invalidateServiceToken(apiKey) {
303
+ const targetKey = apiKey ?? this._serviceApiKey;
304
+ // No specific credential to target — clear everything. The next
305
+ // getServiceToken() for any credential re-mints from scratch.
306
+ if (!targetKey) {
307
+ this._serviceTokenCache.clear();
308
+ return;
309
+ }
310
+ for (const [cacheKey, entry] of this._serviceTokenCache) {
311
+ if (entry.apiKey === targetKey) {
312
+ this._serviceTokenCache.delete(cacheKey);
313
+ return;
314
+ }
315
+ }
316
+ }
317
+ /**
318
+ * Make an authenticated request on behalf of a user using a service token.
319
+ * Automatically obtains/refreshes the service token.
320
+ *
321
+ * @param method - HTTP method
322
+ * @param url - API endpoint URL
323
+ * @param data - Request body or query params
324
+ * @param userId - Optional user ID to act on behalf of (sent as X-Oxy-User-Id)
325
+ */
326
+ async makeServiceRequest(method, url, data, userId) {
327
+ const token = await this.getServiceToken();
328
+ const headers = {
329
+ Authorization: `Bearer ${token}`,
330
+ };
331
+ if (userId) {
332
+ headers['X-Oxy-User-Id'] = userId;
333
+ }
334
+ return this.makeRequest(method, url, data, { headers, cache: false });
335
+ }
336
+ /**
337
+ * Register a new identity with public key authentication
338
+ * Identity is purely cryptographic - username and profile data are optional
339
+ *
340
+ * @param publicKey - The user's ECDSA public key (hex)
341
+ * @param signature - Signature of the registration request
342
+ * @param timestamp - Timestamp when the signature was created
343
+ */
344
+ async register(publicKey, signature, timestamp) {
345
+ try {
346
+ const res = await this.makeRequest('POST', '/auth/register', {
347
+ publicKey,
348
+ signature,
349
+ timestamp,
350
+ }, { cache: false, skipAuth: true });
351
+ if (!res || (typeof res === 'object' && Object.keys(res).length === 0)) {
352
+ throw new OxyServices_errors_1.OxyAuthenticationError('Registration failed', 'REGISTER_FAILED', 400);
353
+ }
354
+ return res;
355
+ }
356
+ catch (error) {
357
+ throw this.handleError(error);
358
+ }
359
+ }
360
+ /**
361
+ * Request an authentication challenge
362
+ * The client must sign this challenge with their private key
363
+ *
364
+ * @param publicKey - The user's public key
365
+ * @param requestOptions - Optional per-call transport overrides (`retry`,
366
+ * `timeout`). Interactive callers omit it (defaults keep retries); the
367
+ * cold-boot `shared-key-signin` step passes `{ retry: false }` so a slow
368
+ * network cannot multiply boot latency via the inner retry loop.
369
+ */
370
+ async requestChallenge(publicKey, requestOptions) {
371
+ try {
372
+ return await this.makeRequest('POST', '/auth/challenge', {
373
+ publicKey,
374
+ }, { cache: false, skipAuth: true, ...requestOptions });
375
+ }
376
+ catch (error) {
377
+ throw this.handleError(error);
378
+ }
379
+ }
380
+ /**
381
+ * Verify a signed challenge and create a session
382
+ *
383
+ * @param publicKey - The user's public key
384
+ * @param challenge - The challenge string from requestChallenge
385
+ * @param signature - Signature of the auth message
386
+ * @param timestamp - Timestamp when the signature was created
387
+ * @param deviceName - Optional device name
388
+ * @param deviceFingerprint - Optional device fingerprint
389
+ * @param requestOptions - Optional per-call transport overrides (`retry`,
390
+ * `timeout`). Interactive callers omit it (defaults keep retries); the
391
+ * cold-boot `shared-key-signin` step passes `{ retry: false }` so a slow
392
+ * network cannot multiply boot latency via the inner retry loop.
393
+ */
394
+ async verifyChallenge(publicKey, challenge, signature, timestamp, deviceName, deviceFingerprint, requestOptions) {
395
+ try {
396
+ const res = await this.makeRequest('POST', '/auth/verify', {
397
+ publicKey,
398
+ challenge,
399
+ signature,
400
+ timestamp,
401
+ deviceName,
402
+ deviceFingerprint,
403
+ }, { cache: false, skipAuth: true, ...requestOptions });
404
+ // Plant the freshly-minted tokens, mirroring `claimSessionByToken`.
405
+ // `/auth/verify` returns the first access token (and refresh token) in
406
+ // its body, so installing it here means callers get an authenticated
407
+ // client without a second round-trip. Refresh stays in the httpOnly
408
+ // cookie slot set by the API.
409
+ if (res?.accessToken) {
410
+ this.setTokens(res.accessToken);
411
+ }
412
+ return {
413
+ ...res,
414
+ user: (0, userIdentity_1.normalizeUserIdentity)(res.user),
415
+ };
416
+ }
417
+ catch (error) {
418
+ throw this.handleError(error);
419
+ }
420
+ }
421
+ /**
422
+ * Check if a public key is already registered
423
+ */
424
+ async checkPublicKeyRegistered(publicKey) {
425
+ try {
426
+ return await this.makeRequest('GET', `/auth/check-publickey/${encodeURIComponent(publicKey)}`, undefined, { cache: false, skipAuth: true });
427
+ }
428
+ catch (error) {
429
+ throw this.handleError(error);
430
+ }
431
+ }
432
+ /**
433
+ * Get user by public key
434
+ */
435
+ async getUserByPublicKey(publicKey) {
436
+ try {
437
+ const user = await this.makeRequest('GET', `/auth/user/${encodeURIComponent(publicKey)}`, undefined, {
438
+ cache: true,
439
+ cacheTTL: 2 * 60 * 1000,
440
+ // Public lookup by public key (pre-session) — skip the bearer preflight.
441
+ skipAuth: true,
442
+ });
443
+ return (0, userIdentity_1.normalizeUserIdentity)(user);
444
+ }
445
+ catch (error) {
446
+ throw this.handleError(error);
447
+ }
448
+ }
449
+ /**
450
+ * Get user by session ID
451
+ */
452
+ async getUserBySession(sessionId) {
453
+ try {
454
+ const user = await this.makeRequest('GET', `/session/user/${sessionId}`, undefined, {
455
+ cache: true,
456
+ cacheTTL: 2 * 60 * 1000,
457
+ });
458
+ return (0, userIdentity_1.normalizeUserIdentity)(user);
459
+ }
460
+ catch (error) {
461
+ throw this.handleError(error);
462
+ }
463
+ }
464
+ /**
465
+ * Batch get multiple user profiles by session IDs
466
+ */
467
+ async getUsersBySessions(sessionIds) {
468
+ try {
469
+ if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
470
+ return [];
471
+ }
472
+ const uniqueSessionIds = Array.from(new Set(sessionIds)).sort();
473
+ const users = await this.makeRequest('POST', '/session/users/batch', { sessionIds: uniqueSessionIds }, {
474
+ cache: true,
475
+ cacheTTL: 2 * 60 * 1000,
476
+ deduplicate: true,
477
+ });
478
+ return users.map((entry) => ({
479
+ ...entry,
480
+ user: (0, userIdentity_1.normalizeUserIdentityOrNull)(entry.user),
481
+ }));
482
+ }
483
+ catch (error) {
484
+ throw this.handleError(error);
485
+ }
486
+ }
487
+ /**
488
+ * Exchange a device-flow sessionToken for the first access token.
489
+ *
490
+ * The originating client holds a 128-bit `sessionToken` that nobody
491
+ * else has seen — it was generated client-side, sent once on
492
+ * `POST /auth/session/create`, and is never echoed back. After
493
+ * another authenticated device approves the session via
494
+ * `POST /auth/session/authorize/{sessionToken}` (bearer-authed) and
495
+ * the auth socket / poll loop notifies this client, the client
496
+ * exchanges its `sessionToken` here for the first access token,
497
+ * refresh token, sessionId, and the authorized user.
498
+ *
499
+ * This call requires no Authorization header — the high-entropy
500
+ * `sessionToken` IS the credential (RFC 8628 §3.4). The exchange is
501
+ * single-use; replay attempts are rejected with 401.
502
+ *
503
+ * @param sessionToken - The same sessionToken the SDK passed to
504
+ * `POST /auth/session/create` at the start of the flow.
505
+ * @param options.deviceFingerprint - Optional fingerprint of the
506
+ * originating client device.
507
+ */
508
+ async claimSessionByToken(sessionToken, options = {}) {
509
+ try {
510
+ const res = await this.makeRequest('POST', '/auth/session/claim', {
511
+ sessionToken,
512
+ ...(options.deviceFingerprint ? { deviceFingerprint: options.deviceFingerprint } : {}),
513
+ },
514
+ // Body-authenticated device-flow claim (no bearer) — skip the preflight.
515
+ { cache: false, retry: false, skipAuth: true });
516
+ this.setTokens(res.accessToken);
517
+ return res;
518
+ }
519
+ catch (error) {
520
+ throw this.handleError(error);
521
+ }
522
+ }
523
+ // =======================================================================
524
+ // "Sign in with Oxy" — handoff (Workstream C)
525
+ //
526
+ // Two mechanisms share the same challenge/verify + device-flow primitives:
527
+ // A. Same-device shared-keychain SSO (`signInWithSharedIdentity`): a
528
+ // sibling native app silently mints its own session from the shared
529
+ // identity key. No user interaction.
530
+ // B. QR / app-to-app / popup / push handoff: a relying party
531
+ // (`startCommonsSignIn` + `pollCommonsSignIn`, finalized with either
532
+ // `claimSessionByToken` or `finalizeCommonsOAuth`) and the approver /
533
+ // Commons (`getCommonsApprovalInfo` + `approveCommonsSignIn` /
534
+ // `denyCommonsSignIn`). The approver signs with its PRIMARY local key;
535
+ // the RP never sees the private key.
536
+ //
537
+ // ONE request serves every delivery surface. The delivery surface is
538
+ // not part of the model: only the request's purpose is, and it is fixed
539
+ // at creation by whether an OAuth binding was attached.
540
+ // =======================================================================
541
+ /**
542
+ * MECHANISM A — same-device shared-keychain SSO.
543
+ *
544
+ * Native-only. If this device holds a shared identity (the cross-app
545
+ * `group.so.oxy.shared` keychain key), prove control of it and mint a
546
+ * session: `requestChallenge(sharedPublicKey)` → `signChallengeWithSharedKey`
547
+ * → `verifyChallenge` (which plants the tokens). Returns `null` on web or
548
+ * when no shared identity is present — never throws for the absent-identity
549
+ * case, so a cold-boot caller can fall through to the next step.
550
+ *
551
+ * The cold-boot wiring that CALLS this lives in `OxyContext`
552
+ * (`@oxy.so/services`); this method just performs the exchange.
553
+ *
554
+ * @param opts.requestOptions - Optional per-call transport overrides
555
+ * (`retry`, `timeout`) forwarded to BOTH the `requestChallenge` and
556
+ * `verifyChallenge` round-trips. Interactive flows omit it (defaults keep
557
+ * retries); the cold-boot `shared-key-signin` step passes `{ retry: false }`
558
+ * so this network step cannot multiply boot latency via the inner retry
559
+ * loop. The token-refresh scheduler / 401 lane still retry later.
560
+ */
561
+ async signInWithSharedIdentity(opts = {}) {
562
+ try {
563
+ // `hasSharedIdentity()` already returns false on web (the shared
564
+ // keychain is native-only), so this short-circuits the web case without
565
+ // a wasted challenge round-trip.
566
+ if (!(await keyManager_1.KeyManager.hasSharedIdentity())) {
567
+ return null;
568
+ }
569
+ const sharedPublicKey = await keyManager_1.KeyManager.getSharedPublicKey();
570
+ if (!sharedPublicKey) {
571
+ return null;
572
+ }
573
+ const { challenge } = await this.requestChallenge(sharedPublicKey, opts.requestOptions);
574
+ const signed = await signatureService_1.SignatureService.signChallengeWithSharedKey(challenge);
575
+ // `signed.challenge` carries the SIGNATURE (mirrors `signChallenge`).
576
+ return await this.verifyChallenge(signed.publicKey, challenge, signed.challenge, signed.timestamp, opts.deviceName, opts.deviceFingerprint, opts.requestOptions);
577
+ }
578
+ catch (error) {
579
+ throw this.handleError(error);
580
+ }
581
+ }
582
+ /**
583
+ * MECHANISM B (relying party) — begin a "Sign in with Oxy" handoff.
584
+ *
585
+ * Generates a secret device-flow `sessionToken` client-side (it never
586
+ * appears in the QR), registers it with `POST /auth/session/create`, and
587
+ * returns the server-issued public `authorizeCode` + ready-to-render
588
+ * `qrPayload`. Render the QR (web) / open the deep-link (same-device); the
589
+ * approver resolves the code and authorizes. Then poll with
590
+ * {@link pollCommonsSignIn} and finalize.
591
+ *
592
+ * ONE request serves every delivery surface, and how it finalizes is decided
593
+ * here by whether an OAuth binding is attached:
594
+ * - no `oauth` (the default): a `device_sign_in` request — on `authorized`,
595
+ * exchange the `sessionToken` via the existing `claimSessionByToken`.
596
+ * - with `oauth`: an `oauth_authorization` request — on `authorized`, call
597
+ * {@link finalizeCommonsOAuth} with the same `sessionToken` to mint the
598
+ * single-use authorization code, then exchange it with PKCE.
599
+ *
600
+ * @param params.clientId - The RP's registered OAuth client id
601
+ * (ApplicationCredential publicKey); required so the server can resolve the
602
+ * requesting application's identity.
603
+ * @param params.oauth - Optional OAuth binding ({@link CommonsOAuthContext}).
604
+ * Carries only the redirect URI, the PKCE S256 challenge, the requested
605
+ * scope, and an optional delegated `subjectAccountId` — never the PKCE
606
+ * verifier, the OAuth `state`, or any token.
607
+ */
608
+ async startCommonsSignIn(params) {
609
+ try {
610
+ // High-entropy opaque secret token (256-bit hex). Generated client-side
611
+ // and held only here; the server stores it but never returns it in the
612
+ // QR. Reuses the platform-safe random generator.
613
+ const sessionToken = await signatureService_1.SignatureService.generateChallenge();
614
+ const expiresAt = Date.now() + COMMONS_SIGN_IN_EXPIRY_MS;
615
+ const res = await this.makeRequest('POST', '/auth/session/create', {
616
+ sessionToken,
617
+ expiresAt,
618
+ clientId: params.clientId,
619
+ // Omitted entirely when absent so the device-sign-in body stays
620
+ // exactly what it has always been (the server reads presence, not a
621
+ // null, to decide the request's purpose).
622
+ ...(params.oauth ? { oauth: params.oauth } : {}),
623
+ },
624
+ // Public/pre-session (no bearer): skip the preflight so a stale
625
+ // near-expiry token cannot re-enter refreshAccessToken while the
626
+ // refresh handler is already in flight (self-await hang).
627
+ { cache: false, skipAuth: true });
628
+ return {
629
+ sessionToken,
630
+ authorizeCode: res.authorizeCode,
631
+ qrPayload: res.qrPayload,
632
+ expiresAt: res.expiresAt ?? expiresAt,
633
+ status: res.status,
634
+ };
635
+ }
636
+ catch (error) {
637
+ throw this.handleError(error);
638
+ }
639
+ }
640
+ /**
641
+ * MECHANISM B (relying party) — poll a device-flow session for approval.
642
+ *
643
+ * Backstop for the auth socket. On `authorized` (with a `sessionId`), the
644
+ * caller finalizes: `claimSessionByToken` for a `device_sign_in` request,
645
+ * {@link finalizeCommonsOAuth} for an `oauth_authorization` one.
646
+ *
647
+ * Every field is narrowed fail-safe. `authorized` counts only as a literal
648
+ * `true`, the identifiers only as non-empty strings, and the delivery
649
+ * progress timestamps degrade to `null` when absent or unparseable — so a
650
+ * partial or older-API payload can advance the waiting UI at most, never
651
+ * make it believe a request was approved.
652
+ *
653
+ * @param sessionToken - The secret token from {@link startCommonsSignIn}.
654
+ */
655
+ async pollCommonsSignIn(sessionToken) {
656
+ try {
657
+ const res = await this.makeRequest('GET', `/auth/session/status/${encodeURIComponent(sessionToken)}`, undefined,
658
+ // Public/pre-session (no bearer): a preflight here is wrong per se and,
659
+ // if ever reached while a refresh is pending, would re-enter
660
+ // refreshAccessToken and await the very promise it runs inside.
661
+ { cache: false, retry: false, skipAuth: true });
662
+ if (res === null || typeof res !== 'object') {
663
+ throw new Error('auth/session/status returned an unexpected response shape');
664
+ }
665
+ const { authorized, sessionId, publicKey, status, purpose, pushSentAt, openedAt } = res;
666
+ return {
667
+ authorized: authorized === true,
668
+ ...(typeof sessionId === 'string' && sessionId ? { sessionId } : {}),
669
+ ...(typeof publicKey === 'string' && publicKey ? { publicKey } : {}),
670
+ ...(typeof status === 'string' && status ? { status } : {}),
671
+ purpose: purpose === 'oauth_authorization' ? 'oauth_authorization' : 'device_sign_in',
672
+ pushSentAt: parseCommonsProgressTimestamp(pushSentAt),
673
+ openedAt: parseCommonsProgressTimestamp(openedAt),
674
+ };
675
+ }
676
+ catch (error) {
677
+ throw this.handleError(error);
678
+ }
679
+ }
680
+ /**
681
+ * MECHANISM B (relying party) — ask Oxy to DELIVER a pending sign-in request
682
+ * to the identity's known Commons installations.
683
+ *
684
+ * This is the automatic half of "one intention, one primary action": rather
685
+ * than offering the user a menu of transports, the caller asks for delivery
686
+ * and lets the answer pick the route. Pass the returned `targets` to
687
+ * `selectCommonsDelivery` (`utils/commonsDelivery`) — `targets: 0` means no
688
+ * capable Commons installation is registered, which is a NORMAL outcome that
689
+ * resolves to the QR route, not an error to surface.
690
+ *
691
+ * **Requires a bearer.** Delivery is only allowed when Oxy already knows the
692
+ * intended identity from a trusted authenticated context — a request that
693
+ * merely carries a username or email typed into an unauthenticated browser
694
+ * must never be able to ring somebody's phone.
695
+ *
696
+ * The push it sends carries only `{ type, approvalUrl }` where the URL holds
697
+ * the public `authorizeCode` — no display data, no secrets. Commons resolves
698
+ * everything it shows from `getCommonsApprovalInfo`.
699
+ *
700
+ * @param authorizeCode - The public code from {@link startCommonsSignIn}.
701
+ */
702
+ async deliverCommonsSignIn(authorizeCode) {
703
+ try {
704
+ const res = await this.makeRequest('POST', `/auth/session/deliver/${encodeURIComponent(authorizeCode)}`, undefined,
705
+ // Bearer REQUIRED (unlike its public siblings): the identity to
706
+ // deliver to comes from the authenticated caller, never the code.
707
+ { cache: false });
708
+ if (res === null || typeof res !== 'object') {
709
+ throw new Error('auth/session/deliver returned an unexpected response shape');
710
+ }
711
+ const { delivered, targets } = res;
712
+ // Both fields drive the route choice, so a partial payload is rejected
713
+ // outright rather than defaulted into a route the server never chose.
714
+ if (typeof delivered !== 'boolean' ||
715
+ typeof targets !== 'number' ||
716
+ !Number.isInteger(targets) ||
717
+ targets < 0) {
718
+ throw new Error('auth/session/deliver returned an incomplete delivery result');
719
+ }
720
+ return { delivered, targets };
721
+ }
722
+ catch (error) {
723
+ throw this.handleError(error);
724
+ }
725
+ }
726
+ /**
727
+ * MECHANISM B (approver / Commons) — report that the approval route was
728
+ * OPENED, so the waiting relying party can show "Opened in Commons".
729
+ *
730
+ * Progress only. It is idempotent, applies to a `pending` request alone, and
731
+ * records a timestamp (`openedAt`) — it never approves, authorizes, or
732
+ * advances the authorization state machine. Public, like the other approver
733
+ * handles: the approver has only the public `authorizeCode` at this point
734
+ * and has not yet signed anything.
735
+ *
736
+ * Best-effort by nature — a failure here costs the user only a progress
737
+ * line, so callers are free to ignore a rejection and continue to the
738
+ * approval screen.
739
+ *
740
+ * @param authorizeCode - The public code scanned from the QR / deep-link / push.
741
+ */
742
+ async markCommonsApprovalOpened(authorizeCode) {
743
+ try {
744
+ await this.makeRequest('POST', `/auth/session/opened/${encodeURIComponent(authorizeCode)}`, undefined,
745
+ // Public (no bearer) — skip the preflight, exactly like approve-info.
746
+ { cache: false, skipAuth: true });
747
+ }
748
+ catch (error) {
749
+ throw this.handleError(error);
750
+ }
751
+ }
752
+ /**
753
+ * MECHANISM B (relying party) — finalize an APPROVED, OAuth-bound request
754
+ * into a single-use OAuth authorization code.
755
+ *
756
+ * The OAuth counterpart of `claimSessionByToken`: same secret credential,
757
+ * same single-use semantics, different output. Call it once the request the
758
+ * RP started with an `oauth` binding reports `authorized`; the server
759
+ * atomically mints exactly ONE `AuthCode` bound to the redirect URI, PKCE
760
+ * challenge, scopes, approving identity, and any delegated subject account
761
+ * the request was created with. A second call cannot mint another code.
762
+ *
763
+ * The result is an authorization CODE, never a token — the caller completes
764
+ * the flow with the ordinary PKCE exchange (`exchangeOAuthCode`) using the
765
+ * `codeVerifier` it never sent anywhere. Nothing here is exposed to the
766
+ * popup: the code travels back through the registered callback, and the
767
+ * main window owns the verifier.
768
+ *
769
+ * Like `claimSessionByToken`, this needs no Authorization header — the
770
+ * high-entropy SECRET `sessionToken` IS the credential. Never pass the
771
+ * public `authorizeCode` here; it is the approver's handle, not the
772
+ * initiator's. Every server-side failure (wrong/expired/already-finalized
773
+ * request, non-OAuth purpose, missing permission for the delegated account)
774
+ * surfaces as one generic error, so nothing about the request's state can be
775
+ * probed from outside.
776
+ *
777
+ * @param sessionToken - The secret token from {@link startCommonsSignIn}.
778
+ */
779
+ async finalizeCommonsOAuth(sessionToken) {
780
+ try {
781
+ const res = await this.makeRequest('POST', `/auth/session/finalize/${encodeURIComponent(sessionToken)}`, undefined,
782
+ // Body-authenticated by the path's secret token (no bearer) — skip the
783
+ // preflight, exactly like the device-flow claim.
784
+ { cache: false, skipAuth: true });
785
+ if (res === null || typeof res !== 'object') {
786
+ throw new Error('auth/session/finalize returned an unexpected response shape');
787
+ }
788
+ const { code, redirectUri, expiresIn } = res;
789
+ // All three fields are load-bearing for the exchange that follows, so a
790
+ // partial payload is rejected outright rather than returned half-parsed.
791
+ if (typeof code !== 'string' ||
792
+ !code ||
793
+ typeof redirectUri !== 'string' ||
794
+ !redirectUri ||
795
+ typeof expiresIn !== 'number' ||
796
+ !Number.isFinite(expiresIn)) {
797
+ throw new Error('auth/session/finalize returned an incomplete authorization code');
798
+ }
799
+ return { code, redirectUri, expiresIn };
800
+ }
801
+ catch (error) {
802
+ throw this.handleError(error);
803
+ }
804
+ }
805
+ /**
806
+ * MECHANISM B (approver / Commons) — resolve the TRUSTED identity of a
807
+ * sign-in request from its public `authorizeCode`.
808
+ *
809
+ * The returned `application` and `subjectAccount` are resolved server-side
810
+ * and are the only safe things to display in the approval UI — NEVER trust
811
+ * the app/name/origin strings carried in the QR payload. Public (no auth
812
+ * required).
813
+ *
814
+ * @param authorizeCode - The public code scanned from the QR / deep-link.
815
+ */
816
+ async getCommonsApprovalInfo(authorizeCode) {
817
+ try {
818
+ const raw = await this.makeRequest('GET', `/auth/session/approve-info/${encodeURIComponent(authorizeCode)}`, undefined,
819
+ // Public (no auth required) — skip the bearer preflight (avoids the
820
+ // pre-session self-await class).
821
+ { cache: false, skipAuth: true });
822
+ return {
823
+ application: raw.application,
824
+ scopes: raw.scopes,
825
+ boundOrigin: raw.boundOrigin,
826
+ // Fail-safe: only a literal boolean `true` counts as verified. A
827
+ // missing or non-boolean value (older server, malformed response)
828
+ // coerces to `false` so a stale server can never imply trust.
829
+ originVerified: raw.originVerified === true,
830
+ // Same discipline: a missing/blank/non-string label degrades to null
831
+ // (an older API, or a native requester with no browser to describe),
832
+ // and the approver simply omits the "where from" line.
833
+ requesterLabel: parseCommonsRequesterLabel(raw.requesterLabel),
834
+ // Same discipline: only the literal OAuth purpose opts into OAuth
835
+ // finalization. Anything else — including a server that predates this
836
+ // field — is the plain device sign-in it has always been.
837
+ purpose: raw.purpose === 'oauth_authorization' ? 'oauth_authorization' : 'device_sign_in',
838
+ // A missing/partial delegated account degrades to "no delegation"
839
+ // rather than a half-rendered "will act as" line.
840
+ subjectAccount: parseCommonsSubjectAccount(raw.subjectAccount),
841
+ expiresAt: raw.expiresAt,
842
+ status: raw.status,
843
+ };
844
+ }
845
+ catch (error) {
846
+ throw this.handleError(error);
847
+ }
848
+ }
849
+ /**
850
+ * MECHANISM B (approver / Commons) — approve a sign-in request by signing a
851
+ * fresh challenge with the PRIMARY local identity key.
852
+ *
853
+ * Commons holds the user's identity as its primary key (not the shared
854
+ * key), so this uses `signChallenge`. The signed-but-cookieless authorize
855
+ * endpoint resolves the user from the verified signer — the RP that started
856
+ * the flow then claims its session. Native-only (requires a local identity).
857
+ *
858
+ * @param params.authorizeCode - The public code being approved.
859
+ * @param params.deviceName - Optional human-readable device label.
860
+ * @param params.deviceFingerprint - Optional device fingerprint.
861
+ */
862
+ async approveCommonsSignIn(params) {
863
+ try {
864
+ const publicKey = await keyManager_1.KeyManager.getPublicKey();
865
+ if (!publicKey) {
866
+ throw new Error('No identity found on this device. Create or import an identity first.');
867
+ }
868
+ const { challenge } = await this.requestChallenge(publicKey);
869
+ const signed = await signatureService_1.SignatureService.signChallenge(challenge);
870
+ return await this.makeRequest('POST', `/auth/session/authorize-signed/${encodeURIComponent(params.authorizeCode)}`, {
871
+ // `signed.challenge` carries the SIGNATURE; `challenge` is the
872
+ // original server-issued challenge string.
873
+ publicKey: signed.publicKey,
874
+ challenge,
875
+ signature: signed.challenge,
876
+ timestamp: signed.timestamp,
877
+ ...(params.deviceName ? { deviceName: params.deviceName } : {}),
878
+ ...(params.deviceFingerprint ? { deviceFingerprint: params.deviceFingerprint } : {}),
879
+ },
880
+ // Key-signed, cookieless (no bearer) — skip the preflight.
881
+ { cache: false, skipAuth: true });
882
+ }
883
+ catch (error) {
884
+ throw this.handleError(error);
885
+ }
886
+ }
887
+ /**
888
+ * MECHANISM B (approver / Commons) — deny a sign-in request, cancelling the
889
+ * device-flow session so the RP stops waiting.
890
+ *
891
+ * @param authorizeCode - The public code being denied.
892
+ * @param reason - Optional closed-set reason ({@link CommonsDenyReason}).
893
+ * Pass `'not_me'` ONLY when the user actually reported the request as one
894
+ * they did not start — the server records it as a suspicious denial rather
895
+ * than an ordinary cancel. Omitting it sends the exact body this endpoint
896
+ * has always received.
897
+ */
898
+ async denyCommonsSignIn(authorizeCode, reason) {
899
+ try {
900
+ return await this.makeRequest('POST', `/auth/session/deny/${encodeURIComponent(authorizeCode)}`, reason ? { reason } : undefined,
901
+ // Public (no auth required) — skip the bearer preflight.
902
+ { cache: false, skipAuth: true });
903
+ }
904
+ catch (error) {
905
+ throw this.handleError(error);
906
+ }
907
+ }
908
+ /**
909
+ * Internal: decode (without verifying) the `sessionId` claim from a
910
+ * server-signed access token. The server already verified the signature;
911
+ * the client only reads the claim to drive multi-session state.
912
+ *
913
+ * @internal
914
+ */
915
+ _decodeSessionIdFromAccessToken(token) {
916
+ if (!token || typeof token !== 'string') {
917
+ return null;
918
+ }
919
+ const segments = token.split('.');
920
+ if (segments.length !== 3) {
921
+ return null;
922
+ }
923
+ const payloadSegment = segments[1];
924
+ if (!payloadSegment) {
925
+ return null;
926
+ }
927
+ try {
928
+ const base64 = payloadSegment.replace(/-/g, '+').replace(/_/g, '/');
929
+ const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');
930
+ if (typeof atob !== 'function') {
931
+ return null;
932
+ }
933
+ const json = decodeURIComponent(atob(padded)
934
+ .split('')
935
+ .map((char) => `%${`00${char.charCodeAt(0).toString(16)}`.slice(-2)}`)
936
+ .join(''));
937
+ const parsed = JSON.parse(json);
938
+ if (parsed === null || typeof parsed !== 'object') {
939
+ return null;
940
+ }
941
+ const claims = parsed;
942
+ return typeof claims.sessionId === 'string' ? claims.sessionId : null;
943
+ }
944
+ catch {
945
+ return null;
946
+ }
947
+ }
948
+ /**
949
+ * Get sessions by session ID
950
+ */
951
+ async getSessionsBySessionId(sessionId) {
952
+ try {
953
+ return await this.makeRequest('GET', `/session/sessions/${sessionId}`, undefined, {
954
+ cache: false,
955
+ });
956
+ }
957
+ catch (error) {
958
+ throw this.handleError(error);
959
+ }
960
+ }
961
+ /**
962
+ * Logout from a specific session
963
+ */
964
+ async logoutSession(sessionId, targetSessionId) {
965
+ try {
966
+ const url = targetSessionId
967
+ ? `/session/logout/${sessionId}/${targetSessionId}`
968
+ : `/session/logout/${sessionId}`;
969
+ await this.makeRequest('POST', url, undefined, { cache: false });
970
+ }
971
+ catch (error) {
972
+ throw this.handleError(error);
973
+ }
974
+ }
975
+ /**
976
+ * Logout from all sessions
977
+ */
978
+ async logoutAllSessions(sessionId) {
979
+ try {
980
+ await this.makeRequest('POST', `/session/logout-all/${sessionId}`, undefined, { cache: false });
981
+ }
982
+ catch (error) {
983
+ throw this.handleError(error);
984
+ }
985
+ }
986
+ /**
987
+ * Validate session
988
+ */
989
+ async validateSession(sessionId, options = {}) {
990
+ try {
991
+ const urlParams = {};
992
+ if (options.deviceFingerprint)
993
+ urlParams.deviceFingerprint = options.deviceFingerprint;
994
+ if (options.useHeaderValidation)
995
+ urlParams.useHeaderValidation = 'true';
996
+ const validation = await this.makeRequest('GET', `/session/validate/${sessionId}`, urlParams, { cache: false });
997
+ return {
998
+ ...validation,
999
+ user: (0, userIdentity_1.normalizeUserIdentity)(validation.user),
1000
+ };
1001
+ }
1002
+ catch (error) {
1003
+ // Session is invalid — clear any cached user data for this session (#196)
1004
+ this.clearCacheEntry(`GET:/session/user/${sessionId}`);
1005
+ throw this.handleError(error);
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Check username availability
1010
+ */
1011
+ async checkUsernameAvailability(username) {
1012
+ try {
1013
+ // Public availability lookup (pre-session) — skip the bearer preflight.
1014
+ return await this.makeRequest('GET', `/auth/check-username/${username}`, undefined, { cache: false, skipAuth: true });
1015
+ }
1016
+ catch (error) {
1017
+ throw this.handleError(error);
1018
+ }
1019
+ }
1020
+ /**
1021
+ * Check email availability
1022
+ */
1023
+ async checkEmailAvailability(email) {
1024
+ try {
1025
+ // Public availability lookup (pre-session) — skip the bearer preflight.
1026
+ return await this.makeRequest('GET', `/auth/check-email/${email}`, undefined, { cache: false, skipAuth: true });
1027
+ }
1028
+ catch (error) {
1029
+ throw this.handleError(error);
1030
+ }
1031
+ }
1032
+ /**
1033
+ * Begin a WebAuthn / passkey REGISTRATION ceremony. Requests the
1034
+ * `PublicKeyCredentialCreationOptions` the browser's `navigator.credentials
1035
+ * .create()` (or `@simplewebauthn/browser`'s `startRegistration`) needs.
1036
+ *
1037
+ * With a bearer token planted this links a passkey to the signed-in account
1038
+ * (`username` ignored); without one it is a prospective signup and `username`
1039
+ * is the desired handle. The returned options are OPAQUE — Oxy does not own
1040
+ * their shape (the browser / `@simplewebauthn` does), so they pass through
1041
+ * as `unknown` for the caller to hand straight to the ceremony.
1042
+ */
1043
+ async webauthnRegisterOptions(username) {
1044
+ try {
1045
+ return await this.makeRequest('POST', '/auth/webauthn/register/options', { ...(username !== undefined ? { username } : {}) }, { cache: false, ...(username !== undefined ? { skipAuth: true } : {}) });
1046
+ }
1047
+ catch (error) {
1048
+ throw this.handleError(error);
1049
+ }
1050
+ }
1051
+ /**
1052
+ * Finish a WebAuthn / passkey REGISTRATION ceremony. Forwards the opaque
1053
+ * browser `RegistrationResponseJSON` (`response`) alongside the Oxy envelope
1054
+ * (desired `username` for signup + the device-session naming fields).
1055
+ *
1056
+ * Two server branches, disambiguated by the response shape:
1057
+ * - **Signup** (no bearer): the account is created and a session minted —
1058
+ * the response carries `sessionId`, is the SAME {@link LoginResult}
1059
+ * contract as `POST /auth/verify`, and its access token is planted here.
1060
+ * - **Link** (bearer present): the passkey is attached to the signed-in
1061
+ * account and the server returns `{ success, message }` with no session,
1062
+ * which is returned verbatim (no token planting).
1063
+ */
1064
+ async webauthnRegisterVerify(response, envelope = {}) {
1065
+ try {
1066
+ const res = await this.makeRequest('POST', '/auth/webauthn/register/verify', { response, ...envelope }, { cache: false, ...(envelope.username !== undefined ? { skipAuth: true } : {}) });
1067
+ if (res && typeof res === 'object') {
1068
+ const record = res;
1069
+ // Signup branch: mints a session (LoginSessionResult, carries
1070
+ // `sessionId`). Parse against the login contract and plant the token.
1071
+ if ('sessionId' in record) {
1072
+ const parsed = (0, contracts_1.safeParseContract)(contracts_1.loginResultSchema, record);
1073
+ if (!parsed) {
1074
+ throw new Error('auth/webauthn/register/verify returned an unexpected response shape');
1075
+ }
1076
+ if (parsed.accessToken) {
1077
+ this.setTokens(parsed.accessToken);
1078
+ }
1079
+ return parsed;
1080
+ }
1081
+ // Link branch: passkey attached to the signed-in account, no session.
1082
+ if (record.success === true && typeof record.message === 'string') {
1083
+ return { success: true, message: record.message };
1084
+ }
1085
+ }
1086
+ throw new Error('auth/webauthn/register/verify returned an unexpected response shape');
1087
+ }
1088
+ catch (error) {
1089
+ throw this.handleError(error);
1090
+ }
1091
+ }
1092
+ /**
1093
+ * Begin a WebAuthn / passkey AUTHENTICATION ceremony. Requests the
1094
+ * `PublicKeyCredentialRequestOptions` the browser's `navigator.credentials
1095
+ * .get()` (or `@simplewebauthn/browser`'s `startAuthentication`) needs.
1096
+ *
1097
+ * When `username` is present the server scopes `allowCredentials` to that
1098
+ * user's passkeys (username-first); when omitted it returns an empty
1099
+ * allow-list for the usernameless / discoverable-credential flow. The
1100
+ * returned options are OPAQUE and pass through as `unknown`.
1101
+ */
1102
+ async webauthnLoginOptions(username) {
1103
+ try {
1104
+ return await this.makeRequest('POST', '/auth/webauthn/login/options', { ...(username !== undefined ? { username } : {}) },
1105
+ // Pre-session login ceremony — skip the bearer preflight.
1106
+ { cache: false, skipAuth: true });
1107
+ }
1108
+ catch (error) {
1109
+ throw this.handleError(error);
1110
+ }
1111
+ }
1112
+ /**
1113
+ * Finish a WebAuthn / passkey AUTHENTICATION ceremony. Forwards the opaque
1114
+ * browser `AuthenticationResponseJSON` (`response`) alongside the
1115
+ * device-session envelope. Resolves to the SAME {@link LoginResult} contract
1116
+ * as `POST /auth/verify`; the access token is planted immediately, and the
1117
+ * response's `deviceId` + `deviceSecret` are the zero-cookie restore
1118
+ * credential.
1119
+ */
1120
+ async webauthnLoginVerify(response, envelope = {}) {
1121
+ try {
1122
+ const res = await this.makeRequest('POST', '/auth/webauthn/login/verify', { response, ...envelope },
1123
+ // Pre-session login ceremony — skip the bearer preflight.
1124
+ { cache: false, skipAuth: true });
1125
+ const parsed = (0, contracts_1.safeParseContract)(contracts_1.loginResultSchema, res);
1126
+ if (!parsed) {
1127
+ throw new Error('auth/webauthn/login/verify returned an unexpected response shape');
1128
+ }
1129
+ if (parsed.accessToken) {
1130
+ this.setTokens(parsed.accessToken);
1131
+ }
1132
+ return parsed;
1133
+ }
1134
+ catch (error) {
1135
+ throw this.handleError(error);
1136
+ }
1137
+ }
1138
+ /**
1139
+ * Exchange an OAuth authorization code (returned to the RP redirect URI
1140
+ * after sign-in at auth.oxy.so) for a device-first session.
1141
+ * Public first-party clients use PKCE (`codeVerifier`); the access token is
1142
+ * planted immediately on success.
1143
+ *
1144
+ * Speaks the standard RFC 6749 §4.1.3 token request — a form-urlencoded
1145
+ * body with snake_case parameters and `grant_type=authorization_code` — and
1146
+ * reads the flat §5.1 response. The camelCase JSON request and `{ data }`
1147
+ * response this method used before were an Oxy invention no OAuth library
1148
+ * could interoperate with; the endpoint no longer accepts them. The method's
1149
+ * OWN signature is unchanged, so callers are unaffected.
1150
+ *
1151
+ * `deviceId` + `deviceSecret` are OPTIONAL and their absence is a valid
1152
+ * outcome, not an error. A third-party grant is meant to be isolated from the
1153
+ * browser's shared DeviceSession, so the token endpoint must be free to return
1154
+ * no device credential at all — the guard that used to require the pair made
1155
+ * that omission unshippable, since it turned every third-party sign-in through
1156
+ * the SDK into a silent `exchange-failed`.
1157
+ *
1158
+ * The cost is real and deliberate: a DEVICE-LESS session cannot use the
1159
+ * zero-cookie mint lane (`POST /session/device/token`), because that lane's
1160
+ * whole proof is possession of a `deviceSecret`. Its lifetime is therefore the
1161
+ * access token itself — nothing persists a restore credential, the cold boot's
1162
+ * `device-secret-mint` step reports `no-secret` and skips, and the refresh
1163
+ * scheduler has nothing to re-mint from. When the token expires the session
1164
+ * ends LOUDLY: the 401 lane clears the tokens and the provider resolves signed
1165
+ * out, so the app can run the OAuth flow again. It never degrades into a
1166
+ * session that looks alive and cannot refresh.
1167
+ */
1168
+ async exchangeOAuthCode(params) {
1169
+ try {
1170
+ const form = new URLSearchParams({
1171
+ grant_type: 'authorization_code',
1172
+ code: params.code,
1173
+ redirect_uri: params.redirectUri,
1174
+ client_id: params.clientId,
1175
+ code_verifier: params.codeVerifier,
1176
+ });
1177
+ const res = await this.makeRequest('POST', '/auth/oauth/token', form, { cache: false, skipAuth: true });
1178
+ if (!res || typeof res !== 'object') {
1179
+ throw new Error('auth/oauth/token returned an unexpected response shape');
1180
+ }
1181
+ // RFC 6749 §5.1: every member sits at the TOP LEVEL of the document.
1182
+ const record = res;
1183
+ const accessToken = typeof record.access_token === 'string' ? record.access_token : undefined;
1184
+ const sessionId = typeof record.session_id === 'string' ? record.session_id : undefined;
1185
+ const deviceId = typeof record.deviceId === 'string' ? record.deviceId : undefined;
1186
+ const deviceSecret = typeof record.deviceSecret === 'string' ? record.deviceSecret : undefined;
1187
+ const userRaw = record.user;
1188
+ // The device pair is NOT part of this guard — see the note above. What is
1189
+ // still mandatory is what identifies the session at all.
1190
+ if (!sessionId || !userRaw || typeof userRaw !== 'object') {
1191
+ throw new Error('auth/oauth/token returned an incomplete session payload');
1192
+ }
1193
+ const userObj = userRaw;
1194
+ const userId = typeof userObj.id === 'string' ? userObj.id : undefined;
1195
+ if (!userId) {
1196
+ throw new Error('auth/oauth/token returned a session without user.id');
1197
+ }
1198
+ const expiresInSec = typeof record.expires_in === 'number' ? record.expires_in : DEFAULT_ACCESS_TOKEN_TTL_SECONDS;
1199
+ const expiresAt = new Date(Date.now() + expiresInSec * 1000).toISOString();
1200
+ if (accessToken) {
1201
+ this.setTokens(accessToken);
1202
+ }
1203
+ if (!deviceId || !deviceSecret) {
1204
+ logger_1.logger.debug('auth/oauth/token returned no device credential — this session lives only as long as its access token', { component: 'oxy.auth', method: 'exchangeOAuthCode' });
1205
+ }
1206
+ return {
1207
+ sessionId,
1208
+ expiresAt,
1209
+ accessToken,
1210
+ // Omitted rather than set to `undefined` when the server sent no device
1211
+ // credential, so a device-less grant serializes as the absence it is.
1212
+ ...(deviceId ? { deviceId } : {}),
1213
+ ...(deviceSecret ? { deviceSecret } : {}),
1214
+ user: {
1215
+ id: userId,
1216
+ username: typeof userObj.username === 'string' ? userObj.username : undefined,
1217
+ avatar: typeof userObj.avatar === 'string' ? userObj.avatar : undefined,
1218
+ },
1219
+ };
1220
+ }
1221
+ catch (error) {
1222
+ throw this.handleError(error);
1223
+ }
1224
+ }
1225
+ /**
1226
+ * Fetch OpenID Connect userinfo for the current bearer (`GET /auth/oauth/userinfo`).
1227
+ * The response is a flat JSON document — no `{ data }` wrapper.
1228
+ */
1229
+ async getOAuthUserInfo() {
1230
+ try {
1231
+ const res = await this.makeRequest('GET', '/auth/oauth/userinfo', undefined, { cache: false });
1232
+ if (!res || typeof res !== 'object') {
1233
+ throw new Error('auth/oauth/userinfo returned an unexpected response shape');
1234
+ }
1235
+ const record = res;
1236
+ const sub = typeof record.sub === 'string' ? record.sub : undefined;
1237
+ if (!sub) {
1238
+ throw new Error('auth/oauth/userinfo returned a response without sub');
1239
+ }
1240
+ return {
1241
+ sub,
1242
+ ...(typeof record.preferred_username === 'string'
1243
+ ? { preferred_username: record.preferred_username }
1244
+ : {}),
1245
+ ...(typeof record.name === 'string' ? { name: record.name } : {}),
1246
+ ...(typeof record.picture === 'string' ? { picture: record.picture } : {}),
1247
+ };
1248
+ }
1249
+ catch (error) {
1250
+ throw this.handleError(error);
1251
+ }
1252
+ }
1253
+ };
1254
+ }