@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,370 @@
1
+ import { OxyServices } from '../OxyServices';
2
+
3
+ interface FetchCall {
4
+ url: string;
5
+ init: RequestInit | undefined;
6
+ }
7
+
8
+ function createServices(): OxyServices {
9
+ return new OxyServices({ baseURL: 'https://api.oxy.so' });
10
+ }
11
+
12
+ function createJwt(payload: Record<string, unknown>): string {
13
+ const encode = (value: unknown): string => Buffer.from(JSON.stringify(value)).toString('base64url');
14
+ return `${encode({ alg: 'HS256', typ: 'JWT' })}.${encode(payload)}.signature`;
15
+ }
16
+
17
+ function jsonResponse(data: unknown): Response {
18
+ return new Response(JSON.stringify({ data }), {
19
+ status: 200,
20
+ headers: { 'content-type': 'application/json' },
21
+ });
22
+ }
23
+
24
+ function readHeaders(init: RequestInit | undefined): Record<string, string> {
25
+ const headers = init?.headers;
26
+ if (!headers) {
27
+ return {};
28
+ }
29
+ if (headers instanceof Headers) {
30
+ return Object.fromEntries(headers.entries());
31
+ }
32
+ if (Array.isArray(headers)) {
33
+ return Object.fromEntries(headers);
34
+ }
35
+ return headers as Record<string, string>;
36
+ }
37
+
38
+ describe('OxyServices.createLinkedClient', () => {
39
+ const originalFetch = globalThis.fetch;
40
+
41
+ afterEach(() => {
42
+ globalThis.fetch = originalFetch;
43
+ jest.restoreAllMocks();
44
+ });
45
+
46
+ it('mirrors token changes from the session owner', () => {
47
+ const oxy = createServices();
48
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.syra.fm' });
49
+
50
+ expect(linked.client.getAccessToken()).toBeNull();
51
+
52
+ oxy.setTokens('access_1');
53
+ expect(linked.client.getAccessToken()).toBe('access_1');
54
+
55
+ oxy.setTokens('access_2');
56
+ expect(linked.client.getAccessToken()).toBe('access_2');
57
+
58
+ oxy.clearTokens();
59
+ expect(linked.client.getAccessToken()).toBeNull();
60
+
61
+ linked.dispose();
62
+ });
63
+
64
+ it('copies the current token when created after sign-in', () => {
65
+ const oxy = createServices();
66
+ oxy.setTokens('existing_access');
67
+
68
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.syra.fm' });
69
+
70
+ expect(linked.client.getAccessToken()).toBe('existing_access');
71
+
72
+ linked.dispose();
73
+ });
74
+
75
+ it('delegates token refresh to the session owner', async () => {
76
+ const oxy = createServices();
77
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.syra.fm' });
78
+
79
+ oxy.getClient().setAuthRefreshHandler(async () => 'refreshed_access');
80
+
81
+ const refreshed = await linked.client.refreshAccessToken('preflight');
82
+
83
+ expect(refreshed).toBe('refreshed_access');
84
+ expect(oxy.getAccessToken()).toBe('refreshed_access');
85
+ expect(linked.client.getAccessToken()).toBe('refreshed_access');
86
+
87
+ linked.dispose();
88
+ });
89
+
90
+ it('returns an unread authenticated streaming response', async () => {
91
+ const calls: FetchCall[] = [];
92
+ globalThis.fetch = async (input, init) => {
93
+ calls.push({ url: String(input), init });
94
+ return new Response('data: {"delta":"hello"}\n\n', {
95
+ status: 200,
96
+ headers: { 'content-type': 'text/event-stream' },
97
+ });
98
+ };
99
+
100
+ const oxy = createServices();
101
+ const accessToken = createJwt({
102
+ userId: 'user_1',
103
+ exp: Math.floor(Date.now() / 1000) + 3600,
104
+ });
105
+ oxy.setTokens(accessToken);
106
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.alia.onl/' });
107
+
108
+ const response = await linked.client.requestAuthenticatedResponse({
109
+ method: 'POST',
110
+ url: '/alia/chat',
111
+ body: JSON.stringify({ message: 'hello' }),
112
+ headers: {
113
+ Authorization: 'Bearer caller_supplied_token',
114
+ 'Content-Type': 'application/json',
115
+ },
116
+ });
117
+
118
+ expect(response.bodyUsed).toBe(false);
119
+ expect(await response.text()).toBe('data: {"delta":"hello"}\n\n');
120
+ expect(calls).toHaveLength(1);
121
+ expect(calls[0]?.url).toBe('https://api.alia.onl/alia/chat');
122
+ expect(readHeaders(calls[0]?.init).authorization).toBe(`Bearer ${accessToken}`);
123
+
124
+ linked.dispose();
125
+ });
126
+
127
+ it('refreshes once after a streaming response 401 and keeps the final body unread', async () => {
128
+ const calls: FetchCall[] = [];
129
+ globalThis.fetch = async (input, init) => {
130
+ calls.push({ url: String(input), init });
131
+ if (calls.length === 1) {
132
+ return new Response('expired', { status: 401 });
133
+ }
134
+ return new Response('data: done\n\n', {
135
+ status: 200,
136
+ headers: { 'content-type': 'text/event-stream' },
137
+ });
138
+ };
139
+
140
+ const oxy = createServices();
141
+ const oldToken = createJwt({
142
+ userId: 'user_1',
143
+ exp: Math.floor(Date.now() / 1000) + 3600,
144
+ });
145
+ const refreshedToken = createJwt({
146
+ userId: 'user_1',
147
+ exp: Math.floor(Date.now() / 1000) + 7200,
148
+ });
149
+ oxy.setTokens(oldToken);
150
+ oxy.getClient().setAuthRefreshHandler(async () => refreshedToken);
151
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.alia.onl' });
152
+
153
+ const response = await linked.client.requestAuthenticatedResponse({
154
+ method: 'POST',
155
+ url: '/alia/chat',
156
+ body: '{}',
157
+ headers: { 'Content-Type': 'application/json' },
158
+ });
159
+
160
+ expect(calls).toHaveLength(2);
161
+ expect(readHeaders(calls[0]?.init).authorization).toBe(`Bearer ${oldToken}`);
162
+ expect(readHeaders(calls[1]?.init).authorization).toBe(`Bearer ${refreshedToken}`);
163
+ expect(oxy.getAccessToken()).toBe(refreshedToken);
164
+ expect(linked.client.getAccessToken()).toBe(refreshedToken);
165
+ expect(response.bodyUsed).toBe(false);
166
+ expect(await response.text()).toBe('data: done\n\n');
167
+
168
+ linked.dispose();
169
+ });
170
+
171
+ it('rejects an authenticated streaming request before fetch without a session', async () => {
172
+ const fetchMock = jest.fn();
173
+ globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch;
174
+ const oxy = createServices();
175
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.alia.onl' });
176
+
177
+ await expect(linked.client.requestAuthenticatedResponse({
178
+ method: 'POST',
179
+ url: '/alia/chat',
180
+ body: '{}',
181
+ })).rejects.toMatchObject({
182
+ code: 'AUTH_REQUIRED',
183
+ status: 401,
184
+ });
185
+ expect(fetchMock).not.toHaveBeenCalled();
186
+
187
+ linked.dispose();
188
+ });
189
+
190
+ it('keeps the session owner intact when a linked response 401 cannot refresh', async () => {
191
+ const oxy = createServices();
192
+ oxy.setTokens('stale_access');
193
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.syra.fm' });
194
+
195
+ const refreshed = await linked.client.refreshAccessToken('response-401');
196
+
197
+ expect(refreshed).toBeNull();
198
+ expect(oxy.getAccessToken()).toBe('stale_access');
199
+ expect(linked.client.getAccessToken()).toBe('stale_access');
200
+
201
+ linked.dispose();
202
+ });
203
+
204
+ it('resynchronizes from the session owner after a linked app 401 clears the local token', async () => {
205
+ const calls: FetchCall[] = [];
206
+ let queueWriteAttempts = 0;
207
+ globalThis.fetch = async (input, init) => {
208
+ const url = String(input);
209
+ calls.push({ url, init });
210
+
211
+ if (url.endsWith('/csrf-token')) {
212
+ return new Response(JSON.stringify({ csrfToken: 'csrf_1' }), {
213
+ status: 200,
214
+ headers: { 'content-type': 'application/json' },
215
+ });
216
+ }
217
+
218
+ if (url.endsWith('/api/queue/current')) {
219
+ queueWriteAttempts += 1;
220
+ if (queueWriteAttempts === 1) {
221
+ return new Response(JSON.stringify({ error: 'MISSING_TOKEN' }), {
222
+ status: 401,
223
+ statusText: 'Unauthorized',
224
+ headers: { 'content-type': 'application/json' },
225
+ });
226
+ }
227
+ }
228
+
229
+ return jsonResponse({ ok: true });
230
+ };
231
+
232
+ const oxy = createServices();
233
+ const accessToken = createJwt({
234
+ userId: 'user_1',
235
+ exp: Math.floor(Date.now() / 1000) + 3600,
236
+ });
237
+ oxy.setTokens(accessToken);
238
+ oxy.getClient().setAuthRefreshHandler(async () => null);
239
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.syra.fm' });
240
+
241
+ await expect(linked.client.put('/api/queue/current', { trackId: 'track_1' }, { retry: false })).rejects.toMatchObject({
242
+ message: 'MISSING_TOKEN',
243
+ status: 401,
244
+ });
245
+
246
+ expect(oxy.getAccessToken()).toBe(accessToken);
247
+ expect(linked.client.getAccessToken()).toBeNull();
248
+
249
+ await linked.client.put('/api/queue/current', { trackId: 'track_2' });
250
+
251
+ expect(calls.map((call) => call.url)).toEqual([
252
+ 'https://api.syra.fm/api/queue/current',
253
+ 'https://api.syra.fm/api/queue/current',
254
+ ]);
255
+ expect(linked.client.getAccessToken()).toBe(accessToken);
256
+
257
+ const firstHeaders = readHeaders(calls[0]?.init);
258
+ expect(firstHeaders.Authorization).toBe(`Bearer ${accessToken}`);
259
+ expect(firstHeaders['X-CSRF-Token']).toBeUndefined();
260
+
261
+ const secondHeaders = readHeaders(calls[1]?.init);
262
+ expect(secondHeaders.Authorization).toBe(`Bearer ${accessToken}`);
263
+ expect(secondHeaders['X-CSRF-Token']).toBeUndefined();
264
+
265
+ linked.dispose();
266
+ });
267
+
268
+ it('keeps the session owner intact when linked preflight refresh cannot refresh', async () => {
269
+ const oxy = createServices();
270
+ oxy.setTokens('existing_access');
271
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.syra.fm' });
272
+
273
+ const refreshed = await linked.client.refreshAccessToken('preflight');
274
+
275
+ expect(refreshed).toBeNull();
276
+ expect(oxy.getAccessToken()).toBe('existing_access');
277
+ expect(linked.client.getAccessToken()).toBe('existing_access');
278
+
279
+ linked.dispose();
280
+ });
281
+
282
+ it('stops mirroring after dispose', () => {
283
+ const oxy = createServices();
284
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.syra.fm' });
285
+
286
+ oxy.setTokens('before_dispose');
287
+ expect(linked.client.getAccessToken()).toBe('before_dispose');
288
+
289
+ linked.dispose();
290
+ oxy.setTokens('after_dispose');
291
+
292
+ expect(linked.client.getAccessToken()).toBeNull();
293
+ });
294
+
295
+ it('joins linked base URLs with relative paths that omit the leading slash', async () => {
296
+ const fetchMock = jest.fn(async () => jsonResponse({ ok: true }));
297
+ globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch;
298
+
299
+ const oxy = createServices();
300
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.mention.earth' });
301
+
302
+ await linked.client.get('profile/settings/me');
303
+
304
+ expect(fetchMock).toHaveBeenCalledTimes(1);
305
+ expect(String(fetchMock.mock.calls[0]?.[0])).toBe('https://api.mention.earth/profile/settings/me');
306
+
307
+ linked.dispose();
308
+ });
309
+
310
+ /**
311
+ * GET response caching is OFF by default for linked clients: the SDK cannot
312
+ * invalidate the consumer backend's resources, so a cached GET there would
313
+ * serve stale data after the app mutates its own data. The consumer's own
314
+ * layer (React Query / stores) owns caching. An explicit `enableCache: true`
315
+ * opts back in.
316
+ */
317
+ describe('linked client GET cache default', () => {
318
+ it('does NOT cache GETs by default — every read hits the network', async () => {
319
+ const fetchMock = jest.fn();
320
+ globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch;
321
+
322
+ const oxy = createServices();
323
+ const accessToken = createJwt({
324
+ userId: 'user_1',
325
+ exp: Math.floor(Date.now() / 1000) + 3600,
326
+ });
327
+ oxy.setTokens(accessToken);
328
+ const linked = oxy.createLinkedClient({ baseURL: 'https://api.mention.earth' });
329
+
330
+ // Two identical GETs with cache:true — both MUST hit the network because
331
+ // the linked client's cache is disabled by default.
332
+ fetchMock.mockResolvedValueOnce(jsonResponse({ v: 1 }));
333
+ const first = await linked.client.get<{ v: number }>('/feed/mtn', { cache: true });
334
+ fetchMock.mockResolvedValueOnce(jsonResponse({ v: 2 }));
335
+ const second = await linked.client.get<{ v: number }>('/feed/mtn', { cache: true });
336
+
337
+ expect(first.v).toBe(1);
338
+ expect(second.v).toBe(2);
339
+ expect(fetchMock).toHaveBeenCalledTimes(2);
340
+
341
+ linked.dispose();
342
+ });
343
+
344
+ it('caches GETs when the caller explicitly opts in with enableCache: true', async () => {
345
+ const fetchMock = jest.fn();
346
+ globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch;
347
+
348
+ const oxy = createServices();
349
+ const accessToken = createJwt({
350
+ userId: 'user_1',
351
+ exp: Math.floor(Date.now() / 1000) + 3600,
352
+ });
353
+ oxy.setTokens(accessToken);
354
+ const linked = oxy.createLinkedClient({
355
+ baseURL: 'https://api.mention.earth',
356
+ enableCache: true,
357
+ });
358
+
359
+ // Second identical GET is a warm cache hit — only one network call.
360
+ fetchMock.mockResolvedValueOnce(jsonResponse({ v: 1 }));
361
+ const first = await linked.client.get<{ v: number }>('/feed/mtn', { cache: true });
362
+ const second = await linked.client.get<{ v: number }>('/feed/mtn', { cache: true });
363
+
364
+ expect(first).toEqual(second);
365
+ expect(fetchMock).toHaveBeenCalledTimes(1);
366
+
367
+ linked.dispose();
368
+ });
369
+ });
370
+ });
@@ -0,0 +1,116 @@
1
+ import { isHttpRequestError, parseHttpErrorBody } from '../utils/errorUtils';
2
+
3
+ /**
4
+ * `parseHttpErrorBody` is the ONE place the SDK decides what a failed request's
5
+ * message, code and details are, across every error envelope the Oxy ecosystem
6
+ * emits. The bug it exists to prevent is silent: a nested
7
+ * `{ error: { code, message } }` assigned straight to `new Error(...)` yields
8
+ * the literal string `"[object Object]"`, which reads as a rendering bug in
9
+ * whichever app surfaces it, arbitrarily far from here.
10
+ *
11
+ * Each case below pins one envelope AND the discrimination it depends on — in
12
+ * particular, whether the top-level `error` string is a machine CODE or human
13
+ * prose is decided solely by whether a sibling human field is present, so both
14
+ * sides of that fork need a fixture or the rule is untested.
15
+ */
16
+ describe('parseHttpErrorBody', () => {
17
+ it('reads the nested { error: { code, message, details } } envelope', () => {
18
+ expect(
19
+ parseHttpErrorBody({
20
+ error: { code: 'case_conflict', message: 'A case already exists', details: { caseId: 'c_1' } },
21
+ }),
22
+ ).toEqual({
23
+ message: 'A case already exists',
24
+ code: 'case_conflict',
25
+ details: { caseId: 'c_1' },
26
+ });
27
+ });
28
+
29
+ it("reads oxy-api's { error: '<CODE>', message } shape — error IS the code", () => {
30
+ expect(parseHttpErrorBody({ error: 'VALIDATION_ERROR', message: 'username is taken' })).toEqual({
31
+ message: 'username is taken',
32
+ code: 'VALIDATION_ERROR',
33
+ details: undefined,
34
+ });
35
+ });
36
+
37
+ it("reads RFC 6749 { error: '<CODE>', error_description } from the OAuth endpoints", () => {
38
+ // The OAuth token/userinfo endpoints are the one part of the API that
39
+ // does not use the `{ error, message }` envelope. Without this arm the
40
+ // human text is dropped and the raw code is shown to the user.
41
+ expect(
42
+ parseHttpErrorBody({ error: 'invalid_grant', error_description: 'Authorization code expired' }),
43
+ ).toEqual({
44
+ message: 'Authorization code expired',
45
+ code: 'invalid_grant',
46
+ details: undefined,
47
+ });
48
+ });
49
+
50
+ it("treats a LONE { error: '<text>' } as the message, never as a code", () => {
51
+ // The discriminator is the ABSENCE of a sibling human field. Promoting a
52
+ // bare string to `code` would put prose where callers switch on codes,
53
+ // so this case and the two above have to disagree.
54
+ expect(parseHttpErrorBody({ error: 'Something went wrong' })).toEqual({
55
+ message: 'Something went wrong',
56
+ code: undefined,
57
+ details: undefined,
58
+ });
59
+ });
60
+
61
+ it('reads the flat { message, code } shape (CSRF rejections)', () => {
62
+ expect(parseHttpErrorBody({ message: 'Invalid CSRF token', code: 'CSRF_TOKEN_INVALID' })).toEqual({
63
+ message: 'Invalid CSRF token',
64
+ code: 'CSRF_TOKEN_INVALID',
65
+ details: undefined,
66
+ });
67
+ });
68
+
69
+ it('ignores whitespace-only strings rather than reporting them as a message', () => {
70
+ // A blank message is worse than none: it replaces the status fallback
71
+ // with an empty error surface the user cannot act on.
72
+ expect(parseHttpErrorBody({ message: ' ', error: '' })).toEqual({
73
+ message: undefined,
74
+ code: undefined,
75
+ details: undefined,
76
+ });
77
+ });
78
+
79
+ it('ignores a non-object `details` instead of passing it through', () => {
80
+ expect(parseHttpErrorBody({ message: 'nope', details: 'not-an-object' }).details).toBeUndefined();
81
+ expect(parseHttpErrorBody({ message: 'nope', details: ['a'] }).details).toBeUndefined();
82
+ });
83
+
84
+ it.each([null, undefined, [], 'a string', 42, true])('returns {} for the non-object body %p', (body) => {
85
+ expect(parseHttpErrorBody(body)).toEqual({});
86
+ });
87
+
88
+ it('returns {} for an object carrying none of the known fields', () => {
89
+ expect(parseHttpErrorBody({ unrelated: 'field' })).toEqual({
90
+ message: undefined,
91
+ code: undefined,
92
+ details: undefined,
93
+ });
94
+ });
95
+ });
96
+
97
+ describe('isHttpRequestError', () => {
98
+ it('accepts an Error carrying a numeric status', () => {
99
+ const error = Object.assign(new Error('boom'), { status: 409 });
100
+ expect(isHttpRequestError(error)).toBe(true);
101
+ });
102
+
103
+ it('rejects a plain ApiError object — those are objects, not Errors', () => {
104
+ // The distinction is load-bearing: an ApiError has to go through
105
+ // `handleHttpError` first, and a truthy answer here would let a caller
106
+ // read `.stack`/`.name` off something that has neither.
107
+ expect(isHttpRequestError({ message: 'boom', status: 409, code: 'CONFLICT' })).toBe(false);
108
+ });
109
+
110
+ it('rejects an Error whose status is a non-number', () => {
111
+ // `'409'` is the shape a hand-built error most plausibly carries, and
112
+ // the narrowing promises callers a number they can compare.
113
+ expect(isHttpRequestError(Object.assign(new Error('boom'), { status: '409' }))).toBe(false);
114
+ expect(isHttpRequestError(new Error('boom'))).toBe(false);
115
+ });
116
+ });
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Every package `@oxy.so/core/server` VALUE-imports must be a real dependency.
3
+ *
4
+ * ## The failure this exists for, which happened
5
+ *
6
+ * `helmet` was declared an OPTIONAL peer dependency. `src/server/securityHeaders.ts`
7
+ * imports it at the top level, and the server barrel re-exports that module — so
8
+ * importing *anything* from `@oxy.so/core/server` loads helmet, and a consumer
9
+ * that believed the "optional" marking did not install it.
10
+ *
11
+ * The result was a backend that could not boot: `Cannot find package 'helmet'`.
12
+ * `tsc` passed clean the whole time, because types resolve from a peer whether
13
+ * or not the runtime can find the module. It was found by a test suite failing
14
+ * to resolve 29 of 63 files while every typecheck was green — which is a very
15
+ * expensive way to learn it.
16
+ *
17
+ * ## Why value imports and not all imports
18
+ *
19
+ * `express` is imported by eight files here and every one of them is
20
+ * `import type`. Those vanish at build time, so an optional peer is a truthful
21
+ * declaration for it: a consumer of the client entry never needs express
22
+ * installed. The distinction this test draws is exactly the one that decides
23
+ * whether a missing package is a warning or a crash.
24
+ */
25
+
26
+ import { readFileSync, readdirSync } from 'node:fs';
27
+ import path from 'node:path';
28
+
29
+ const packageRoot = path.resolve(__dirname, '../..');
30
+ const serverDir = path.join(packageRoot, 'src', 'server');
31
+
32
+ const manifest = JSON.parse(readFileSync(path.join(packageRoot, 'package.json'), 'utf8')) as {
33
+ dependencies?: Record<string, string>;
34
+ peerDependencies?: Record<string, string>;
35
+ peerDependenciesMeta?: Record<string, { optional?: boolean }>;
36
+ };
37
+
38
+ const dependencies = new Set(Object.keys(manifest.dependencies ?? {}));
39
+ const requiredPeers = new Set(
40
+ Object.keys(manifest.peerDependencies ?? {}).filter(
41
+ (name) => manifest.peerDependenciesMeta?.[name]?.optional !== true
42
+ )
43
+ );
44
+
45
+ /**
46
+ * Bare specifiers imported for their VALUE — `import x from 'y'`,
47
+ * `import { a } from 'y'`, `import 'y'` — but never `import type`.
48
+ */
49
+ function valueImports(source: string): string[] {
50
+ const found: string[] = [];
51
+ // Strip comments first: prose in a doc comment can otherwise read as code.
52
+ const code = source.replace(/\/\*[\s\S]*?\*\//g, ' ').replace(/(^|[^:])\/\/[^\n]*/g, '$1 ');
53
+ for (const match of code.matchAll(/import\s+(?!type\b)([^;']*?)from\s*'([^']+)'/g)) {
54
+ // `import { type A, type B } from 'x'` is still type-only in effect.
55
+ const clause = match[1];
56
+ const specifier = match[2];
57
+ if (specifier.startsWith('.') || specifier.startsWith('node:')) continue;
58
+ const names = clause.replace(/[{}]/g, '').split(',').map((n) => n.trim()).filter(Boolean);
59
+ if (names.length > 0 && names.every((n) => n.startsWith('type '))) continue;
60
+ found.push(specifier);
61
+ }
62
+ for (const match of code.matchAll(/import\s*'([^']+)'/g)) {
63
+ if (!match[1].startsWith('.') && !match[1].startsWith('node:')) found.push(match[1]);
64
+ }
65
+ return found;
66
+ }
67
+
68
+ function packageNameOf(specifier: string): string {
69
+ const parts = specifier.split('/');
70
+ return specifier.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0];
71
+ }
72
+
73
+ const files = readdirSync(serverDir).filter((f) => f.endsWith('.ts') && !f.endsWith('.d.ts'));
74
+
75
+ describe('@oxy.so/core/server value imports are installable', () => {
76
+ it('reads a non-trivial number of server modules', () => {
77
+ // Vacuity floor: a traversal that found nothing would satisfy every
78
+ // assertion below by having nothing to check.
79
+ expect(files.length).toBeGreaterThan(5);
80
+ });
81
+
82
+ it('declares every value-imported package as a dependency or a REQUIRED peer', () => {
83
+ const undeclared: string[] = [];
84
+ for (const file of files) {
85
+ const source = readFileSync(path.join(serverDir, file), 'utf8');
86
+ for (const specifier of valueImports(source)) {
87
+ const name = packageNameOf(specifier);
88
+ if (dependencies.has(name) || requiredPeers.has(name)) continue;
89
+ undeclared.push(`${file} → ${name}`);
90
+ }
91
+ }
92
+
93
+ // An OPTIONAL peer is not enough here and that is the whole point: the
94
+ // module is loaded the moment anything is imported from the server barrel,
95
+ // so "optional" describes a package the consumer cannot actually omit.
96
+ expect(undeclared.sort()).toEqual([]);
97
+ });
98
+
99
+ it('keeps helmet installable rather than optional', () => {
100
+ // The specific regression, asserted by name so a failure says what broke
101
+ // rather than only showing it inside a list.
102
+ expect(dependencies.has('helmet')).toBe(true);
103
+ expect(manifest.peerDependenciesMeta?.helmet?.optional).toBeUndefined();
104
+ });
105
+
106
+ it('keeps express-rate-limit installable rather than a peer', () => {
107
+ // Same class as helmet: `rateLimit.ts` value-imports it and the server
108
+ // barrel re-exports that module, so a missing install crashes at boot.
109
+ expect(dependencies.has('express-rate-limit')).toBe(true);
110
+ expect(manifest.peerDependencies?.['express-rate-limit']).toBeUndefined();
111
+ });
112
+
113
+ it('leaves express as an optional peer, because it is type-only here', () => {
114
+ // The counter-example that stops this test from being read as "declare
115
+ // everything": type imports vanish at build time, so an optional peer is a
116
+ // truthful declaration for express and making it required would nag every
117
+ // React Native consumer about a package they never load.
118
+ expect(manifest.peerDependenciesMeta?.express?.optional).toBe(true);
119
+ });
120
+ });