@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,888 @@
1
+ /**
2
+ * The Oxy inference client — one surface, two credential lanes (issue #972,
3
+ * workstream 15).
4
+ *
5
+ * ```typescript
6
+ * // An OpenAI-style machine key: one bearer string, no session, no exchange.
7
+ * const oxy = new OxyInferenceClient({ credential: process.env.OXY_API_KEY });
8
+ *
9
+ * // Oxy auth: whatever bearer the session or the service-token mint holds.
10
+ * const oxy = oxyServices.inference();
11
+ * ```
12
+ *
13
+ * Both lanes reach the SAME endpoints and are told apart only by how the bearer
14
+ * is produced: a machine key is a constant string, and an Oxy bearer rotates, so
15
+ * it is a function this client calls on every request rather than a value it
16
+ * captures once. There is no third lane, and no method behaves differently
17
+ * depending on which one you used.
18
+ *
19
+ * `respond()` returns one completed response. `stream()` reads the same
20
+ * `/v1/responses` endpoint without buffering and validates every SSE event
21
+ * against `inferenceStreamEventSchema` before exposing it to the caller.
22
+ *
23
+ * ## Why this is a client and not more methods on `OxyServices`
24
+ *
25
+ * Two reasons, both structural. A machine-key holder has no Oxy session at all,
26
+ * so a surface reached only through the session client would be unreachable for
27
+ * exactly the developer this workstream exists to serve. And the `/v1` error
28
+ * body is the contract's `InferenceError` at the top level rather than the
29
+ * platform's `{ error, message }` envelope — it carries `requestId`, `retryable`
30
+ * and `retryAfterMs`, all of which `OxyServices.handleError` would flatten into a
31
+ * message string. `oxyServices.inference()` binds the session bearer into this
32
+ * client so a session-holding app writes no plumbing of its own.
33
+ *
34
+ * ## Streaming is an explicit method
35
+ *
36
+ * `stream()` injects `stream: true` on the wire. The request type deliberately
37
+ * has no `stream` field, so `respond({ stream: true })` cannot promise a JSON
38
+ * response while the server sends SSE, and `stream({ stream: false })` cannot
39
+ * silently buffer. The method is the transport choice.
40
+ *
41
+ * ## Field names, and the one place they could drift
42
+ *
43
+ * Every VALUE type here comes from `@oxy.so/contracts` — messages, tools, tool
44
+ * choice, response format, usage quantities, unit prices, error codes. The
45
+ * request FIELD NAMES cannot: they belong to `responsesRequestSchema`, which
46
+ * lives in the API because it is a public dialect rather than an Oxy↔data-plane
47
+ * contract. `packages/api/src/schemas/__tests__/sdkRequestCompatibility.test.ts`
48
+ * is the gate — it parses a value of this module's request type against that
49
+ * schema, so a rename on either side fails a build rather than a customer's
50
+ * request.
51
+ */
52
+
53
+ import type {
54
+ CurrencyCode,
55
+ ExactDecimal,
56
+ InferenceEnvironment,
57
+ InferenceErrorCode,
58
+ InferenceFinishReason,
59
+ InferenceMessage,
60
+ InferenceRequestOutcome,
61
+ InferenceStreamEvent,
62
+ ModelCatalogueEntry,
63
+ ResponseFormat,
64
+ RoutingPolicyReference,
65
+ RoutingProfile,
66
+ ToolChoice,
67
+ ToolDefinition,
68
+ UnitPrice,
69
+ UsageQuantity,
70
+ UsageSource,
71
+ } from '@oxy.so/contracts';
72
+ import { INFERENCE_ERROR_CODES, inferenceStreamEventSchema, modelIdSchema } from '@oxy.so/contracts';
73
+
74
+ /** The base URL of the Oxy API, when a caller names none. */
75
+ export const OXY_INFERENCE_BASE_URL = 'https://api.oxy.so';
76
+
77
+ /**
78
+ * How this client gets its bearer.
79
+ *
80
+ * A `string` is a static machine credential (`oxy_sk_…`) — presented verbatim,
81
+ * exactly as a stock OpenAI SDK would present it. A function is the Oxy auth
82
+ * lane and is called on EVERY request, because a session bearer and a service
83
+ * token both rotate and a captured one goes stale inside the hour.
84
+ */
85
+ export type OxyInferenceCredential =
86
+ | string
87
+ | (() => string | null | Promise<string | null>);
88
+
89
+ /**
90
+ * The `fetch` this client calls.
91
+ *
92
+ * The global signature rather than a narrowed one, so any drop-in
93
+ * implementation — a test double, an instrumented wrapper, a Node agent — is
94
+ * assignable without a cast at either end.
95
+ */
96
+ export type OxyInferenceFetch = typeof fetch;
97
+
98
+ export interface OxyInferenceClientOptions {
99
+ readonly credential: OxyInferenceCredential;
100
+ /** Defaults to {@link OXY_INFERENCE_BASE_URL}. A trailing slash is trimmed. */
101
+ readonly baseURL?: string;
102
+ /** Defaults to the global `fetch`. */
103
+ readonly fetch?: OxyInferenceFetch;
104
+ }
105
+
106
+ /**
107
+ * A request to `POST /v1/responses`.
108
+ *
109
+ * `model`, `routingProfile`, and `routingProfileId` are mutually exclusive and
110
+ * all are optional: an
111
+ * application whose routing policy carries a `defaultTarget` may name neither,
112
+ * which is what "per-application default model or routing profile" means. Naming
113
+ * both is refused by the edge with `invalid_request`.
114
+ */
115
+ export interface OxyResponsesRequest {
116
+ /** `<publisher>/<model>` or `<publisher>/<model>@<revision>`. */
117
+ readonly model?: string;
118
+ /** A routing profile slug. Never contains a slash, so it is never a model id. */
119
+ readonly routingProfile?: string;
120
+ /** An exact opaque routing-profile database ID; serialized byte-for-byte. */
121
+ readonly routingProfileId?: string;
122
+ /** A prompt, or the message list it is shorthand for. */
123
+ readonly input: string | readonly InferenceMessage[];
124
+ readonly maxOutputTokens?: number;
125
+ readonly temperature?: number;
126
+ readonly topP?: number;
127
+ readonly topK?: number;
128
+ readonly frequencyPenalty?: number;
129
+ readonly presencePenalty?: number;
130
+ readonly seed?: number;
131
+ readonly stopSequences?: readonly string[];
132
+ readonly tools?: readonly ToolDefinition[];
133
+ readonly toolChoice?: ToolChoice;
134
+ readonly responseFormat?: ResponseFormat;
135
+ /** Cost-attribution tags, echoed back on the receipt. At most 16. */
136
+ readonly labels?: Readonly<Record<string, string>>;
137
+ /** Your own correlation id, echoed on the response. */
138
+ readonly clientRequestId?: string;
139
+ }
140
+
141
+ export interface OxyInferenceRequestOptions {
142
+ /**
143
+ * Abort the request. The edge treats a client disconnect as a cancellation:
144
+ * it settles what was produced and refunds the rest, so a cancelled request
145
+ * is a normal terminal state rather than an error to clean up after.
146
+ */
147
+ readonly signal?: AbortSignal;
148
+ /**
149
+ * `Idempotency-Key`. A key already bound to a reservation is REFUSED with
150
+ * `idempotency_conflict` rather than replayed — responses are not retained,
151
+ * so there is nothing to replay, and refusing is what makes "a retry never
152
+ * produces a second charge" structural. At most 128 characters.
153
+ */
154
+ readonly idempotencyKey?: string;
155
+ /**
156
+ * `X-Oxy-User-Id` — the end user this request is made on behalf of.
157
+ * ATTRIBUTION ONLY: it never changes which account is charged.
158
+ */
159
+ readonly delegatedUserId?: string;
160
+ }
161
+
162
+ /** The body of a successful `POST /v1/responses`. */
163
+ export interface OxyInferenceResponse {
164
+ readonly schemaVersion: 1;
165
+ /** Also on `X-Oxy-Request-Id`, on success and on every refusal. */
166
+ readonly requestId: string;
167
+ readonly generationId?: string;
168
+ /** Always revision-pinned, even when you named only the model line. */
169
+ readonly model: string;
170
+ readonly servingProvider: string;
171
+ readonly finishReason: InferenceFinishReason;
172
+ readonly output: readonly InferenceMessage[];
173
+ /** Metered quantities. Never money — the charge is on the receipt. */
174
+ readonly usage: readonly UsageQuantity[];
175
+ /** The exact policy version this request was admitted under. */
176
+ readonly routingPolicy: RoutingPolicyReference;
177
+ /**
178
+ * How long Oxy took over this request, in whole milliseconds — also on
179
+ * `X-Oxy-Latency-Ms`.
180
+ *
181
+ * Measured from the moment the edge received the request through
182
+ * authentication, admission, routing, the reservation, the call to the
183
+ * inference data plane and the settlement of the hold. Most of it is the
184
+ * upstream generating tokens; it does not separate the two.
185
+ *
186
+ * It is NOT the round trip you can measure yourself, which additionally
187
+ * covers DNS, TLS, both network legs and your own parse. Report them side by
188
+ * side rather than picking one — this figure has no network in it and yours
189
+ * cannot be attributed to the model.
190
+ *
191
+ * Optional because it is additive: an Oxy deployment older than the field
192
+ * omits it, and a streamed request never carries it (the head is written
193
+ * before the first frame arrives, so the number does not exist yet).
194
+ */
195
+ readonly latencyMs?: number;
196
+ }
197
+
198
+ /**
199
+ * A settled receipt, as `GET /v1/generations/:id` returns it.
200
+ *
201
+ * Carries the price SNAPSHOT rather than a reference to a price version, so the
202
+ * arithmetic stays checkable after that version has been superseded.
203
+ */
204
+ export interface OxyGenerationReceipt {
205
+ readonly schemaVersion: 1;
206
+ readonly receiptId: string;
207
+ readonly requestId: string;
208
+ readonly generationId?: string;
209
+ readonly applicationId: string;
210
+ readonly credentialId: string;
211
+ /** Attribution only. Never the billing identity. */
212
+ readonly delegatedUserId?: string;
213
+ readonly environment: InferenceEnvironment;
214
+ readonly outcome: InferenceRequestOutcome;
215
+ readonly usageSource: UsageSource;
216
+ /** EVERY unit, including the zeros — see `usageSource` for what a zero means. */
217
+ readonly units: readonly UsageQuantity[];
218
+ readonly resolvedModelReference: string;
219
+ readonly servingProvider: string;
220
+ readonly priceSnapshot: {
221
+ readonly priceVersionId: string;
222
+ readonly currency: CurrencyCode;
223
+ readonly unitPrices: readonly UnitPrice[];
224
+ };
225
+ readonly billedAmount: ExactDecimal;
226
+ readonly currency: CurrencyCode;
227
+ /** A BYOK route: `billedAmount` is Oxy's fee, not the cost of the tokens. */
228
+ readonly platformFeeOnly: boolean;
229
+ readonly settledAt: string;
230
+ }
231
+
232
+ /**
233
+ * Anything the inference API refused.
234
+ *
235
+ * `retryable` is asserted by the server and looked up from a total map over the
236
+ * closed code set — never inferred here from the status. A client that decides
237
+ * retryability from an HTTP status is exactly what the contract's retryability
238
+ * rule exists to prevent, so this class carries the server's answer and does not
239
+ * compute one.
240
+ */
241
+ export class OxyInferenceError extends Error {
242
+ readonly code: InferenceErrorCode;
243
+ readonly retryable: boolean;
244
+ readonly requestId: string;
245
+ readonly status: number;
246
+ /** How long to wait. Only ever present when `retryable`. */
247
+ readonly retryAfterMs?: number;
248
+ /** The request field at fault, for `invalid_request`. */
249
+ readonly param?: string;
250
+
251
+ constructor(input: {
252
+ code: InferenceErrorCode;
253
+ message: string;
254
+ retryable: boolean;
255
+ requestId: string;
256
+ status: number;
257
+ retryAfterMs?: number;
258
+ param?: string;
259
+ }) {
260
+ super(input.message);
261
+ this.name = 'OxyInferenceError';
262
+ this.code = input.code;
263
+ this.retryable = input.retryable;
264
+ this.requestId = input.requestId;
265
+ this.status = input.status;
266
+ if (input.retryAfterMs !== undefined) this.retryAfterMs = input.retryAfterMs;
267
+ if (input.param !== undefined) this.param = input.param;
268
+ }
269
+ }
270
+
271
+ /**
272
+ * The edge opened an SSE response but its framing or one of its events violated
273
+ * the published inference stream contract.
274
+ *
275
+ * This is distinct from {@link OxyInferenceError}: the latter is a refusal the
276
+ * server deliberately returned, while this error means the client could not
277
+ * safely interpret a nominally successful stream.
278
+ */
279
+ export class OxyInferenceProtocolError extends Error {
280
+ /** The request id from the response header, when the edge supplied one. */
281
+ readonly requestId?: string;
282
+
283
+ constructor(message: string, requestId?: string) {
284
+ super(message);
285
+ this.name = 'OxyInferenceProtocolError';
286
+ if (requestId !== undefined) this.requestId = requestId;
287
+ }
288
+ }
289
+
290
+ /** `{ data, count }` — the catalogue's collection envelope. */
291
+ interface CatalogueCollection<T> {
292
+ data: T[];
293
+ count: number;
294
+ }
295
+
296
+ /** The shape `/v1/responses` and `/v1/generations/:id` return on a refusal. */
297
+ interface WireInferenceError {
298
+ schemaVersion?: number;
299
+ code?: string;
300
+ message?: string;
301
+ retryable?: boolean;
302
+ requestId?: string;
303
+ retryAfterMs?: number;
304
+ param?: string;
305
+ }
306
+
307
+ /**
308
+ * The Oxy inference API.
309
+ *
310
+ * Stateless: it holds a base URL, a way to get a bearer and a `fetch`. Nothing
311
+ * is cached, because the two things worth caching here are a catalogue that is
312
+ * audience-scoped and a receipt that is immutable but rarely re-read.
313
+ *
314
+ * Completed JSON responses are TYPED, not re-parsed. The server validates every
315
+ * one against its own schema before serving it, and a second client-side parse
316
+ * of a non-strict shape would silently DROP fields a newer API added — turning
317
+ * forward compatibility into data loss. Stream events are different: each is a
318
+ * versioned wire message and is parsed against the shared contract before it is
319
+ * yielded. Refusals are read defensively, because two routers answer under `/v1`
320
+ * and an unreadable failure must still reach the caller as one.
321
+ */
322
+ export class OxyInferenceClient {
323
+ readonly #baseURL: string;
324
+ readonly #credential: OxyInferenceCredential;
325
+ readonly #fetch: OxyInferenceFetch;
326
+
327
+ constructor(options: OxyInferenceClientOptions) {
328
+ const baseURL = options.baseURL ?? OXY_INFERENCE_BASE_URL;
329
+ this.#baseURL = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL;
330
+ this.#credential = options.credential;
331
+
332
+ const fetchImpl = options.fetch ?? globalThis.fetch;
333
+ if (fetchImpl === undefined) {
334
+ throw new Error(
335
+ 'OxyInferenceClient needs a fetch implementation: this runtime has no global fetch, so pass one as `fetch`.',
336
+ );
337
+ }
338
+ this.#fetch = fetchImpl;
339
+ }
340
+
341
+ /**
342
+ * The models this caller may use — `GET /v1/models`.
343
+ *
344
+ * Audience-scoped server-side. A machine credential and an anonymous caller
345
+ * both see the PUBLIC catalogue; only an internal/system application's
346
+ * service token sees internal-only routes.
347
+ *
348
+ * **`[]` is a normal answer**, and is the only answer today: the catalogue
349
+ * is populated by operators, and a route is not publicly exposed until
350
+ * somebody has reviewed the right to resell it.
351
+ */
352
+ async listModels(options: { signal?: AbortSignal } = {}): Promise<ModelCatalogueEntry[]> {
353
+ const body = await this.#request<CatalogueCollection<ModelCatalogueEntry>>(
354
+ 'GET',
355
+ '/v1/models',
356
+ { ...(options.signal === undefined ? {} : { signal: options.signal }) },
357
+ );
358
+ return body.data;
359
+ }
360
+
361
+ /**
362
+ * One catalogue entry by its canonical id — `GET /v1/models/:publisher/:model`.
363
+ *
364
+ * The id is TWO path segments, because a canonical model id contains a slash
365
+ * and a single encoded segment would never match the route.
366
+ *
367
+ * A model you may not see answers 404 identically to one that does not
368
+ * exist, deliberately: the catalogue is never an existence oracle for what
369
+ * Oxy runs internally.
370
+ *
371
+ * @param modelId - `<publisher>/<model>`. A revision pin
372
+ * (`<publisher>/<model>@<revision>`) names a model REFERENCE rather than a
373
+ * model and is rejected here rather than sent, because the catalogue is
374
+ * keyed on models and a pinned reference would 404 indistinguishably from
375
+ * "no such model".
376
+ */
377
+ async getModel(
378
+ modelId: string,
379
+ options: { signal?: AbortSignal } = {},
380
+ ): Promise<ModelCatalogueEntry> {
381
+ const parsed = modelIdSchema.safeParse(modelId);
382
+ if (!parsed.success) {
383
+ throw new Error(
384
+ `Not a canonical model id: ${modelId}. Expected <publisher>/<model>, e.g. acme/some-model.`,
385
+ );
386
+ }
387
+
388
+ const [publisher, model] = parsed.data.split('/');
389
+ const body = await this.#request<{ data: ModelCatalogueEntry }>(
390
+ 'GET',
391
+ `/v1/models/${encodeURIComponent(publisher)}/${encodeURIComponent(model)}`,
392
+ { ...(options.signal === undefined ? {} : { signal: options.signal }) },
393
+ );
394
+ return body.data;
395
+ }
396
+
397
+ /**
398
+ * The routing profiles this caller may select — `GET /v1/models/routing-profiles`.
399
+ *
400
+ * A profile is a named strategy for CHOOSING among routes, not a model: no
401
+ * publisher, no revision, no licence, no weights. Like the model list, `[]`
402
+ * is a normal answer.
403
+ */
404
+ async listRoutingProfiles(
405
+ options: { signal?: AbortSignal } = {},
406
+ ): Promise<RoutingProfile[]> {
407
+ const body = await this.#request<CatalogueCollection<RoutingProfile>>(
408
+ 'GET',
409
+ '/v1/models/routing-profiles',
410
+ { ...(options.signal === undefined ? {} : { signal: options.signal }) },
411
+ );
412
+ return body.data;
413
+ }
414
+
415
+ /**
416
+ * Send one non-streaming inference request — `POST /v1/responses`.
417
+ *
418
+ * @throws {OxyInferenceError} for every refusal, carrying the server's own
419
+ * `code`, `retryable` and `requestId`.
420
+ */
421
+ async respond(
422
+ request: OxyResponsesRequest,
423
+ options: OxyInferenceRequestOptions = {},
424
+ ): Promise<OxyInferenceResponse> {
425
+ return this.#request<OxyInferenceResponse>('POST', '/v1/responses', {
426
+ body: request,
427
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
428
+ ...(options.idempotencyKey === undefined
429
+ ? {}
430
+ : { idempotencyKey: options.idempotencyKey }),
431
+ ...(options.delegatedUserId === undefined
432
+ ? {}
433
+ : { delegatedUserId: options.delegatedUserId }),
434
+ });
435
+ }
436
+
437
+ /**
438
+ * Stream one inference request from `POST /v1/responses`.
439
+ *
440
+ * The transport choice is method-level: this method adds `stream: true` and
441
+ * requests SSE, while {@link respond} never does. Every yielded value has
442
+ * already passed `inferenceStreamEventSchema`, belongs to the request id in
443
+ * the response header and advances the stream sequence. A terminal `error`
444
+ * event is yielded as part of the published union; an HTTP refusal before
445
+ * the stream opens throws {@link OxyInferenceError}.
446
+ *
447
+ * Breaking out of the iterator cancels the response body. Passing an abort
448
+ * signal additionally lets the caller cancel while waiting for the first or
449
+ * any later event.
450
+ *
451
+ * @throws {OxyInferenceError} when the edge refuses before opening SSE.
452
+ * @throws {OxyInferenceProtocolError} when a successful SSE response cannot
453
+ * be interpreted under the published stream contract.
454
+ */
455
+ async *stream(
456
+ request: OxyResponsesRequest,
457
+ options: OxyInferenceRequestOptions = {},
458
+ ): AsyncGenerator<InferenceStreamEvent> {
459
+ const response = await this.#fetch(`${this.#baseURL}/v1/responses`, {
460
+ method: 'POST',
461
+ headers: await this.#headers('text/event-stream', {
462
+ hasBody: true,
463
+ ...(options.idempotencyKey === undefined
464
+ ? {}
465
+ : { idempotencyKey: options.idempotencyKey }),
466
+ ...(options.delegatedUserId === undefined
467
+ ? {}
468
+ : { delegatedUserId: options.delegatedUserId }),
469
+ }),
470
+ body: JSON.stringify({ ...request, stream: true }),
471
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
472
+ });
473
+
474
+ if (!response.ok) {
475
+ const payload: unknown = await response.json().catch(() => undefined);
476
+ throw toInferenceError(
477
+ payload,
478
+ response.status,
479
+ response.headers.get('X-Oxy-Request-Id'),
480
+ );
481
+ }
482
+
483
+ const requestId = response.headers.get('X-Oxy-Request-Id') ?? undefined;
484
+ const mediaType = response.headers
485
+ .get('Content-Type')
486
+ ?.split(';', 1)[0]
487
+ ?.trim()
488
+ .toLowerCase();
489
+ if (mediaType !== 'text/event-stream') {
490
+ await cancelUnreadResponse(response);
491
+ throw protocolError(
492
+ `The inference API answered a streaming request with ${mediaType ?? 'no Content-Type'} instead of text/event-stream.`,
493
+ requestId,
494
+ );
495
+ }
496
+ if (requestId === undefined || requestId.length === 0) {
497
+ await cancelUnreadResponse(response);
498
+ throw protocolError(
499
+ 'The inference API opened a stream without X-Oxy-Request-Id.',
500
+ requestId,
501
+ );
502
+ }
503
+ if (response.body === null) {
504
+ throw protocolError(
505
+ 'The inference API opened a stream with no response body.',
506
+ requestId,
507
+ );
508
+ }
509
+
510
+ let lastSequence = -1;
511
+ let terminal = false;
512
+ for await (const frame of decodeEventStream(response.body, requestId)) {
513
+ if (terminal) {
514
+ throw protocolError(
515
+ 'The inference API sent an event after a terminal event.',
516
+ requestId,
517
+ );
518
+ }
519
+
520
+ let payload: unknown;
521
+ try {
522
+ payload = JSON.parse(frame.data);
523
+ } catch (_error) {
524
+ throw protocolError(
525
+ `The inference API sent a ${frame.name || 'unnamed'} SSE event that is not JSON.`,
526
+ requestId,
527
+ );
528
+ }
529
+
530
+ const parsed = inferenceStreamEventSchema.safeParse(payload);
531
+ if (!parsed.success) {
532
+ const path = parsed.error.issues[0]?.path;
533
+ throw protocolError(
534
+ `The inference API sent an event outside the published stream contract at ${path === undefined || path.length === 0 ? 'an unknown field' : path.join('.')}.`,
535
+ requestId,
536
+ );
537
+ }
538
+
539
+ const event = parsed.data;
540
+ if (frame.name !== event.type) {
541
+ throw protocolError(
542
+ `The inference API framed a ${event.type} event as ${frame.name || 'unnamed'}.`,
543
+ requestId,
544
+ );
545
+ }
546
+ if (event.requestId !== requestId) {
547
+ throw protocolError(
548
+ 'The inference API sent an event for a different request id.',
549
+ requestId,
550
+ );
551
+ }
552
+ if (event.sequence <= lastSequence) {
553
+ throw protocolError(
554
+ 'The inference API sent a stream sequence that did not advance.',
555
+ requestId,
556
+ );
557
+ }
558
+
559
+ lastSequence = event.sequence;
560
+ terminal = event.type === 'done' || event.type === 'error';
561
+ yield event;
562
+ }
563
+
564
+ if (!terminal) {
565
+ throw protocolError(
566
+ 'The inference API closed the stream before a terminal done or error event.',
567
+ requestId,
568
+ );
569
+ }
570
+ }
571
+
572
+ /**
573
+ * Read back the settled receipt for one request —
574
+ * `GET /v1/generations/:id`.
575
+ *
576
+ * `id` is the `requestId` you already hold (it is on every response and
577
+ * every error) or the `generationId`. Requires the `inference:usage:read`
578
+ * scope; a caller without it, or one whose application did not make the
579
+ * request, is told the receipt does not exist rather than that it belongs to
580
+ * somebody else.
581
+ */
582
+ async getGeneration(
583
+ id: string,
584
+ options: { signal?: AbortSignal } = {},
585
+ ): Promise<OxyGenerationReceipt> {
586
+ const body = await this.#request<{ data: OxyGenerationReceipt }>(
587
+ 'GET',
588
+ `/v1/generations/${encodeURIComponent(id)}`,
589
+ { ...(options.signal === undefined ? {} : { signal: options.signal }) },
590
+ );
591
+ return body.data;
592
+ }
593
+
594
+ /** The bearer for this request, from whichever lane was configured. */
595
+ async #bearer(): Promise<string> {
596
+ const value =
597
+ typeof this.#credential === 'string'
598
+ ? this.#credential
599
+ : await this.#credential();
600
+ if (value === null || value === undefined || value.length === 0) {
601
+ throw new Error(
602
+ 'OxyInferenceClient has no bearer: the configured credential resolved to nothing. On the Oxy auth lane this usually means the session is not restored yet.',
603
+ );
604
+ }
605
+ return value;
606
+ }
607
+
608
+ /** Build the authenticated headers for one request, re-reading its bearer. */
609
+ async #headers(
610
+ accept: 'application/json' | 'text/event-stream',
611
+ options: {
612
+ hasBody: boolean;
613
+ idempotencyKey?: string;
614
+ delegatedUserId?: string;
615
+ },
616
+ ): Promise<Record<string, string>> {
617
+ const headers: Record<string, string> = {
618
+ Authorization: `Bearer ${await this.#bearer()}`,
619
+ Accept: accept,
620
+ };
621
+ if (options.hasBody) headers['Content-Type'] = 'application/json';
622
+ if (options.idempotencyKey !== undefined) {
623
+ headers['Idempotency-Key'] = options.idempotencyKey;
624
+ }
625
+ if (options.delegatedUserId !== undefined) {
626
+ headers['X-Oxy-User-Id'] = options.delegatedUserId;
627
+ }
628
+ return headers;
629
+ }
630
+
631
+ /**
632
+ * One request, and the one place a refusal becomes an
633
+ * {@link OxyInferenceError}.
634
+ *
635
+ * Two error shapes arrive here, because two routers serve `/v1`. The edge
636
+ * returns the contract error at the top level; the catalogue returns the
637
+ * platform's `{ error, message }` envelope. Both are read, and a body that
638
+ * is neither still produces an `OxyInferenceError` — with the code the
639
+ * status maps to — rather than a bare `Error`, so a caller's `catch` never
640
+ * has to branch on which router answered.
641
+ */
642
+ async #request<T>(
643
+ method: 'GET' | 'POST',
644
+ path: string,
645
+ options: {
646
+ body?: unknown;
647
+ signal?: AbortSignal;
648
+ idempotencyKey?: string;
649
+ delegatedUserId?: string;
650
+ },
651
+ ): Promise<T> {
652
+ const response = await this.#fetch(`${this.#baseURL}${path}`, {
653
+ method,
654
+ headers: await this.#headers('application/json', {
655
+ hasBody: options.body !== undefined,
656
+ ...(options.idempotencyKey === undefined
657
+ ? {}
658
+ : { idempotencyKey: options.idempotencyKey }),
659
+ ...(options.delegatedUserId === undefined
660
+ ? {}
661
+ : { delegatedUserId: options.delegatedUserId }),
662
+ }),
663
+ ...(options.body === undefined ? {} : { body: JSON.stringify(options.body) }),
664
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
665
+ });
666
+
667
+ const payload: unknown = await response.json().catch(() => undefined);
668
+
669
+ if (!response.ok) {
670
+ throw toInferenceError(
671
+ payload,
672
+ response.status,
673
+ response.headers.get('X-Oxy-Request-Id'),
674
+ );
675
+ }
676
+
677
+ return payload as T;
678
+ }
679
+ }
680
+
681
+ /** Bound one public SSE event before parsing it as JSON. */
682
+ const MAX_INFERENCE_STREAM_EVENT_CHARACTERS = 8 * 1024 * 1024;
683
+
684
+ /** Bound the `data:` array too; empty lines consume memory without characters. */
685
+ const MAX_INFERENCE_STREAM_EVENT_DATA_LINES = 4096;
686
+
687
+ /** One SSE frame after transport decoding and before contract validation. */
688
+ interface RawInferenceStreamFrame {
689
+ readonly name: string;
690
+ readonly data: string;
691
+ }
692
+
693
+ function protocolError(message: string, requestId?: string): OxyInferenceProtocolError {
694
+ return new OxyInferenceProtocolError(message, requestId);
695
+ }
696
+
697
+ /** Cancel a nominally successful response whose stream contract is unreadable. */
698
+ async function cancelUnreadResponse(response: Response): Promise<void> {
699
+ await response.body?.cancel().catch(() => undefined);
700
+ }
701
+
702
+ /**
703
+ * Decode SSE incrementally, preserving chunk boundaries only until a complete
704
+ * line is available.
705
+ *
706
+ * Multiple `data:` lines join with a newline, comments are ignored and a final
707
+ * frame does not need a trailing blank line. Cancelling the iterator cancels the
708
+ * body reader, which is how breaking out of `for await` closes the HTTP request
709
+ * instead of leaving generation running upstream.
710
+ */
711
+ async function* decodeEventStream(
712
+ body: ReadableStream<Uint8Array>,
713
+ requestId: string,
714
+ ): AsyncGenerator<RawInferenceStreamFrame> {
715
+ const reader = body.getReader();
716
+ const decoder = new TextDecoder('utf-8', { fatal: true });
717
+ let pending = '';
718
+ let name = '';
719
+ let data: string[] = [];
720
+ let accumulated = 0;
721
+ let dataLines = 0;
722
+ let reachedEnd = false;
723
+
724
+ const decode = (chunk?: Uint8Array, options?: TextDecodeOptions): string => {
725
+ try {
726
+ return decoder.decode(chunk, options);
727
+ } catch (_error) {
728
+ throw protocolError(
729
+ 'The inference API sent an SSE stream that is not valid UTF-8.',
730
+ requestId,
731
+ );
732
+ }
733
+ };
734
+
735
+ const dispatch = (): RawInferenceStreamFrame | undefined => {
736
+ if (data.length === 0 && name.length === 0) return undefined;
737
+ const frame = { name, data: data.join('\n') };
738
+ name = '';
739
+ data = [];
740
+ accumulated = 0;
741
+ dataLines = 0;
742
+ return frame;
743
+ };
744
+
745
+ const consume = (raw: string): RawInferenceStreamFrame | undefined => {
746
+ const line = raw.endsWith('\r') ? raw.slice(0, -1) : raw;
747
+ if (line.length === 0) return dispatch();
748
+ if (line.startsWith(':')) return undefined;
749
+
750
+ const separator = line.indexOf(':');
751
+ const field = separator === -1 ? line : line.slice(0, separator);
752
+ const rawValue = separator === -1 ? '' : line.slice(separator + 1);
753
+ const value = rawValue.startsWith(' ') ? rawValue.slice(1) : rawValue;
754
+
755
+ if (field === 'data') {
756
+ dataLines += 1;
757
+ if (dataLines > MAX_INFERENCE_STREAM_EVENT_DATA_LINES) {
758
+ throw protocolError(
759
+ `The inference API sent an SSE event with over ${MAX_INFERENCE_STREAM_EVENT_DATA_LINES} data lines.`,
760
+ requestId,
761
+ );
762
+ }
763
+ accumulated += value.length;
764
+ if (accumulated > MAX_INFERENCE_STREAM_EVENT_CHARACTERS) {
765
+ throw protocolError(
766
+ `The inference API sent an SSE event over ${MAX_INFERENCE_STREAM_EVENT_CHARACTERS} characters.`,
767
+ requestId,
768
+ );
769
+ }
770
+ data.push(value);
771
+ } else if (field === 'event') {
772
+ name = value.trim();
773
+ }
774
+ return undefined;
775
+ };
776
+
777
+ try {
778
+ for (;;) {
779
+ const chunk = await reader.read();
780
+ if (chunk.done) {
781
+ reachedEnd = true;
782
+ break;
783
+ }
784
+
785
+ pending += decode(chunk.value, { stream: true });
786
+ if (pending.length > MAX_INFERENCE_STREAM_EVENT_CHARACTERS) {
787
+ throw protocolError(
788
+ `The inference API sent an SSE line over ${MAX_INFERENCE_STREAM_EVENT_CHARACTERS} characters with no boundary.`,
789
+ requestId,
790
+ );
791
+ }
792
+
793
+ let newline = pending.indexOf('\n');
794
+ while (newline !== -1) {
795
+ const frame = consume(pending.slice(0, newline));
796
+ pending = pending.slice(newline + 1);
797
+ if (frame !== undefined) yield frame;
798
+ newline = pending.indexOf('\n');
799
+ }
800
+ }
801
+
802
+ pending += decode();
803
+ if (pending.length > 0) {
804
+ const frame = consume(pending);
805
+ if (frame !== undefined) yield frame;
806
+ }
807
+ const trailing = dispatch();
808
+ if (trailing !== undefined) yield trailing;
809
+ } finally {
810
+ if (!reachedEnd) {
811
+ // Preserve the original parse/abort error if transport cancellation
812
+ // itself also refuses: cancellation is cleanup, never the diagnosis.
813
+ await reader.cancel().catch(() => undefined);
814
+ }
815
+ reader.releaseLock();
816
+ }
817
+ }
818
+
819
+ /**
820
+ * Which code a status means when the body did not name one.
821
+ *
822
+ * Deliberately partial: only the statuses whose meaning is unambiguous without a
823
+ * body. Everything else becomes `internal_error`, which is non-retryable — the
824
+ * safe direction, since inventing a retryable code for an unreadable failure is
825
+ * how one outage becomes a retry storm.
826
+ */
827
+ const STATUS_FALLBACK_CODE: Readonly<Record<number, InferenceErrorCode>> = {
828
+ 400: 'invalid_request',
829
+ 401: 'authentication_failed',
830
+ 403: 'permission_denied',
831
+ 404: 'model_not_found',
832
+ 409: 'idempotency_conflict',
833
+ 413: 'request_too_large',
834
+ 429: 'rate_limited',
835
+ 502: 'provider_error',
836
+ 503: 'service_unavailable',
837
+ 504: 'provider_timeout',
838
+ };
839
+
840
+ /**
841
+ * The closed set the contract defines, as a lookup.
842
+ *
843
+ * A `code` outside it is a contract violation rather than a code this client
844
+ * has not caught up with — `INFERENCE_ERROR_CODES` and the version header move
845
+ * together — so an unrecognised one falls back to the status map instead of
846
+ * being asserted into the type.
847
+ */
848
+ const INFERENCE_ERROR_CODE_SET: ReadonlySet<string> = new Set<string>(INFERENCE_ERROR_CODES);
849
+
850
+ /** Read whichever error shape arrived into the one this client throws. */
851
+ function toInferenceError(
852
+ payload: unknown,
853
+ status: number,
854
+ requestIdHeader: string | null,
855
+ ): OxyInferenceError {
856
+ const body = (payload ?? {}) as WireInferenceError & { error?: unknown };
857
+
858
+ // The edge's own shape is the contract error at the top level; the
859
+ // catalogue's is the platform envelope, whose `error` is a string.
860
+ const code =
861
+ typeof body.code === 'string' && INFERENCE_ERROR_CODE_SET.has(body.code)
862
+ ? (body.code as InferenceErrorCode)
863
+ : (STATUS_FALLBACK_CODE[status] ?? 'internal_error');
864
+
865
+ const message =
866
+ typeof body.message === 'string' && body.message.length > 0
867
+ ? body.message
868
+ : typeof body.error === 'string' && body.error.length > 0
869
+ ? body.error
870
+ : `The inference API answered ${status}.`;
871
+
872
+ return new OxyInferenceError({
873
+ code,
874
+ message,
875
+ // A body that did not assert retryability is not retryable: the server
876
+ // is the only thing that may say a retry could succeed.
877
+ retryable: body.retryable === true,
878
+ requestId:
879
+ typeof body.requestId === 'string' && body.requestId.length > 0
880
+ ? body.requestId
881
+ : (requestIdHeader ?? ''),
882
+ status,
883
+ ...(body.retryable === true && typeof body.retryAfterMs === 'number'
884
+ ? { retryAfterMs: body.retryAfterMs }
885
+ : {}),
886
+ ...(typeof body.param === 'string' ? { param: body.param } : {}),
887
+ });
888
+ }