@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.
- package/LICENSE +202 -0
- package/NOTICE +16 -0
- package/README.md +221 -0
- package/dist/cjs/.tsbuildinfo +1 -0
- package/dist/cjs/HttpService.js +1270 -0
- package/dist/cjs/OxyServices.base.js +390 -0
- package/dist/cjs/OxyServices.errors.js +95 -0
- package/dist/cjs/OxyServices.js +72 -0
- package/dist/cjs/boot/sessionColdBoot.js +395 -0
- package/dist/cjs/constants/version.js +16 -0
- package/dist/cjs/crypto/aead.js +79 -0
- package/dist/cjs/crypto/ecdh.js +35 -0
- package/dist/cjs/crypto/identityMarker.js +255 -0
- package/dist/cjs/crypto/kdf.js +39 -0
- package/dist/cjs/crypto/keyManager.js +2234 -0
- package/dist/cjs/crypto/polyfill.js +131 -0
- package/dist/cjs/crypto/recoveryPhrase.js +242 -0
- package/dist/cjs/crypto/signatureService.js +273 -0
- package/dist/cjs/i18n/accountCategoryLabels.js +44 -0
- package/dist/cjs/i18n/accountRoleLabels.js +27 -0
- package/dist/cjs/i18n/index.js +90 -0
- package/dist/cjs/i18n/locales/ar-SA.json +282 -0
- package/dist/cjs/i18n/locales/ca-ES.json +282 -0
- package/dist/cjs/i18n/locales/de-DE.json +282 -0
- package/dist/cjs/i18n/locales/en-US.json +2161 -0
- package/dist/cjs/i18n/locales/es-ES.json +2161 -0
- package/dist/cjs/i18n/locales/fr-FR.json +282 -0
- package/dist/cjs/i18n/locales/it-IT.json +282 -0
- package/dist/cjs/i18n/locales/ja-JP.json +282 -0
- package/dist/cjs/i18n/locales/ko-KR.json +282 -0
- package/dist/cjs/i18n/locales/locales/ar-SA.json +282 -0
- package/dist/cjs/i18n/locales/locales/ca-ES.json +282 -0
- package/dist/cjs/i18n/locales/locales/de-DE.json +282 -0
- package/dist/cjs/i18n/locales/locales/en-US.json +2161 -0
- package/dist/cjs/i18n/locales/locales/es-ES.json +2161 -0
- package/dist/cjs/i18n/locales/locales/fr-FR.json +282 -0
- package/dist/cjs/i18n/locales/locales/it-IT.json +282 -0
- package/dist/cjs/i18n/locales/locales/ja-JP.json +282 -0
- package/dist/cjs/i18n/locales/locales/ko-KR.json +282 -0
- package/dist/cjs/i18n/locales/locales/pt-PT.json +282 -0
- package/dist/cjs/i18n/locales/locales/zh-CN.json +282 -0
- package/dist/cjs/i18n/locales/pt-PT.json +282 -0
- package/dist/cjs/i18n/locales/zh-CN.json +282 -0
- package/dist/cjs/i18n/reputationCategoryLabels.js +20 -0
- package/dist/cjs/i18n/trustTierLabels.js +19 -0
- package/dist/cjs/index.js +498 -0
- package/dist/cjs/inference/OxyInferenceClient.js +544 -0
- package/dist/cjs/logger/index.js +149 -0
- package/dist/cjs/mixins/OxyServices.accounts.js +555 -0
- package/dist/cjs/mixins/OxyServices.analytics.js +49 -0
- package/dist/cjs/mixins/OxyServices.appData.js +108 -0
- package/dist/cjs/mixins/OxyServices.assets.js +764 -0
- package/dist/cjs/mixins/OxyServices.auth.js +1254 -0
- package/dist/cjs/mixins/OxyServices.chains.js +73 -0
- package/dist/cjs/mixins/OxyServices.civic.js +611 -0
- package/dist/cjs/mixins/OxyServices.connectedApps.js +78 -0
- package/dist/cjs/mixins/OxyServices.contacts.js +50 -0
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +191 -0
- package/dist/cjs/mixins/OxyServices.deviceTransfer.js +314 -0
- package/dist/cjs/mixins/OxyServices.devices.js +116 -0
- package/dist/cjs/mixins/OxyServices.features.js +335 -0
- package/dist/cjs/mixins/OxyServices.followGraph.js +221 -0
- package/dist/cjs/mixins/OxyServices.identity.js +461 -0
- package/dist/cjs/mixins/OxyServices.identityBackup.js +172 -0
- package/dist/cjs/mixins/OxyServices.inference.js +59 -0
- package/dist/cjs/mixins/OxyServices.language.js +125 -0
- package/dist/cjs/mixins/OxyServices.links.js +72 -0
- package/dist/cjs/mixins/OxyServices.location.js +43 -0
- package/dist/cjs/mixins/OxyServices.nodes.js +175 -0
- package/dist/cjs/mixins/OxyServices.notifications.js +63 -0
- package/dist/cjs/mixins/OxyServices.payment.js +158 -0
- package/dist/cjs/mixins/OxyServices.privacy.js +199 -0
- package/dist/cjs/mixins/OxyServices.reputation.js +289 -0
- package/dist/cjs/mixins/OxyServices.security.js +89 -0
- package/dist/cjs/mixins/OxyServices.store.js +266 -0
- package/dist/cjs/mixins/OxyServices.topics.js +137 -0
- package/dist/cjs/mixins/OxyServices.user.js +902 -0
- package/dist/cjs/mixins/OxyServices.utility.js +1098 -0
- package/dist/cjs/mixins/index.js +135 -0
- package/dist/cjs/mixins/mixinHelpers.js +53 -0
- package/dist/cjs/models/Topic.js +16 -0
- package/dist/cjs/models/interfaces.js +20 -0
- package/dist/cjs/models/session.js +2 -0
- package/dist/cjs/server/auth.js +167 -0
- package/dist/cjs/server/capabilityTicket.js +192 -0
- package/dist/cjs/server/cors.js +225 -0
- package/dist/cjs/server/index.js +97 -0
- package/dist/cjs/server/rateLimit.js +207 -0
- package/dist/cjs/server/safeFetch.js +458 -0
- package/dist/cjs/server/securityHeaders.js +377 -0
- package/dist/cjs/server/userInvalidation.js +156 -0
- package/dist/cjs/server/verifySecret.js +50 -0
- package/dist/cjs/session/SessionClient.js +865 -0
- package/dist/cjs/session/accountDelegationAccess.js +48 -0
- package/dist/cjs/session/accountDialogController.js +1131 -0
- package/dist/cjs/session/accountSwitchTargets.js +81 -0
- package/dist/cjs/session/authStateStore.js +404 -0
- package/dist/cjs/session/createSessionClient.js +32 -0
- package/dist/cjs/session/deviceDirectory.js +143 -0
- package/dist/cjs/session/deviceSwitcherRows.js +76 -0
- package/dist/cjs/session/identityPin.js +256 -0
- package/dist/cjs/session/identitySession.js +135 -0
- package/dist/cjs/session/projectSessionState.js +121 -0
- package/dist/cjs/session/refresh.js +398 -0
- package/dist/cjs/session/sessionClientHost.js +34 -0
- package/dist/cjs/session/sharedDeviceCredential.js +247 -0
- package/dist/cjs/session/socketLoader.js +55 -0
- package/dist/cjs/shared/utils/colorUtils.js +153 -0
- package/dist/cjs/shared/utils/errorUtils.js +183 -0
- package/dist/cjs/shared/utils/index.js +49 -0
- package/dist/cjs/shared/utils/networkUtils.js +183 -0
- package/dist/cjs/shared/utils/themeUtils.js +106 -0
- package/dist/cjs/utils/accountCacheSweep.js +80 -0
- package/dist/cjs/utils/accountUtils.js +140 -0
- package/dist/cjs/utils/activityId.js +6 -0
- package/dist/cjs/utils/apiUtils.js +91 -0
- package/dist/cjs/utils/asyncUtils.js +222 -0
- package/dist/cjs/utils/authHelpers.js +120 -0
- package/dist/cjs/utils/authWebUrl.js +19 -0
- package/dist/cjs/utils/avatarUtils.js +29 -0
- package/dist/cjs/utils/cache.js +235 -0
- package/dist/cjs/utils/cacheKey.js +85 -0
- package/dist/cjs/utils/coldBoot.js +122 -0
- package/dist/cjs/utils/commonsApproval.js +31 -0
- package/dist/cjs/utils/commonsDelivery.js +59 -0
- package/dist/cjs/utils/deviceManager.js +174 -0
- package/dist/cjs/utils/displayNamePolicyRanges.generated.js +60 -0
- package/dist/cjs/utils/edgeRegion.js +6 -0
- package/dist/cjs/utils/errorUtils.js +243 -0
- package/dist/cjs/utils/identityCacheSweep.js +97 -0
- package/dist/cjs/utils/languageUtils.js +224 -0
- package/dist/cjs/utils/oauthPkce.js +311 -0
- package/dist/cjs/utils/officialOrigins.js +64 -0
- package/dist/cjs/utils/oxyServiceEnvironment.js +19 -0
- package/dist/cjs/utils/platform.js +119 -0
- package/dist/cjs/utils/profileLinks.js +63 -0
- package/dist/cjs/utils/redactUrl.js +29 -0
- package/dist/cjs/utils/registrableApex.js +45 -0
- package/dist/cjs/utils/requestUtils.js +209 -0
- package/dist/cjs/utils/sessionUtils.js +181 -0
- package/dist/cjs/utils/textNormalization.js +158 -0
- package/dist/cjs/utils/userHandle.js +37 -0
- package/dist/cjs/utils/userIdentity.js +50 -0
- package/dist/cjs/utils/validationUtils.js +370 -0
- package/dist/cjs/utils/webauthnOrigin.js +51 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/dist/esm/HttpService.js +1266 -0
- package/dist/esm/OxyServices.base.js +386 -0
- package/dist/esm/OxyServices.errors.js +88 -0
- package/dist/esm/OxyServices.js +66 -0
- package/dist/esm/boot/sessionColdBoot.js +392 -0
- package/dist/esm/constants/version.js +13 -0
- package/dist/esm/crypto/aead.js +74 -0
- package/dist/esm/crypto/ecdh.js +32 -0
- package/dist/esm/crypto/identityMarker.js +248 -0
- package/dist/esm/crypto/kdf.js +36 -0
- package/dist/esm/crypto/keyManager.js +2227 -0
- package/dist/esm/crypto/polyfill.js +129 -0
- package/dist/esm/crypto/recoveryPhrase.js +238 -0
- package/dist/esm/crypto/signatureService.js +269 -0
- package/dist/esm/i18n/accountCategoryLabels.js +37 -0
- package/dist/esm/i18n/accountRoleLabels.js +20 -0
- package/dist/esm/i18n/index.js +83 -0
- package/dist/esm/i18n/locales/ar-SA.json +282 -0
- package/dist/esm/i18n/locales/ca-ES.json +282 -0
- package/dist/esm/i18n/locales/de-DE.json +282 -0
- package/dist/esm/i18n/locales/en-US.json +2161 -0
- package/dist/esm/i18n/locales/es-ES.json +2161 -0
- package/dist/esm/i18n/locales/fr-FR.json +282 -0
- package/dist/esm/i18n/locales/it-IT.json +282 -0
- package/dist/esm/i18n/locales/ja-JP.json +282 -0
- package/dist/esm/i18n/locales/ko-KR.json +282 -0
- package/dist/esm/i18n/locales/locales/ar-SA.json +282 -0
- package/dist/esm/i18n/locales/locales/ca-ES.json +282 -0
- package/dist/esm/i18n/locales/locales/de-DE.json +282 -0
- package/dist/esm/i18n/locales/locales/en-US.json +2161 -0
- package/dist/esm/i18n/locales/locales/es-ES.json +2161 -0
- package/dist/esm/i18n/locales/locales/fr-FR.json +282 -0
- package/dist/esm/i18n/locales/locales/it-IT.json +282 -0
- package/dist/esm/i18n/locales/locales/ja-JP.json +282 -0
- package/dist/esm/i18n/locales/locales/ko-KR.json +282 -0
- package/dist/esm/i18n/locales/locales/pt-PT.json +282 -0
- package/dist/esm/i18n/locales/locales/zh-CN.json +282 -0
- package/dist/esm/i18n/locales/pt-PT.json +282 -0
- package/dist/esm/i18n/locales/zh-CN.json +282 -0
- package/dist/esm/i18n/reputationCategoryLabels.js +13 -0
- package/dist/esm/i18n/trustTierLabels.js +12 -0
- package/dist/esm/index.js +254 -0
- package/dist/esm/inference/OxyInferenceClient.js +538 -0
- package/dist/esm/logger/index.js +140 -0
- package/dist/esm/mixins/OxyServices.accounts.js +543 -0
- package/dist/esm/mixins/OxyServices.analytics.js +46 -0
- package/dist/esm/mixins/OxyServices.appData.js +103 -0
- package/dist/esm/mixins/OxyServices.assets.js +761 -0
- package/dist/esm/mixins/OxyServices.auth.js +1247 -0
- package/dist/esm/mixins/OxyServices.chains.js +70 -0
- package/dist/esm/mixins/OxyServices.civic.js +605 -0
- package/dist/esm/mixins/OxyServices.connectedApps.js +75 -0
- package/dist/esm/mixins/OxyServices.contacts.js +47 -0
- package/dist/esm/mixins/OxyServices.deviceBoot.js +186 -0
- package/dist/esm/mixins/OxyServices.deviceTransfer.js +311 -0
- package/dist/esm/mixins/OxyServices.devices.js +113 -0
- package/dist/esm/mixins/OxyServices.features.js +332 -0
- package/dist/esm/mixins/OxyServices.followGraph.js +218 -0
- package/dist/esm/mixins/OxyServices.identity.js +457 -0
- package/dist/esm/mixins/OxyServices.identityBackup.js +169 -0
- package/dist/esm/mixins/OxyServices.inference.js +56 -0
- package/dist/esm/mixins/OxyServices.language.js +122 -0
- package/dist/esm/mixins/OxyServices.links.js +69 -0
- package/dist/esm/mixins/OxyServices.location.js +40 -0
- package/dist/esm/mixins/OxyServices.nodes.js +172 -0
- package/dist/esm/mixins/OxyServices.notifications.js +60 -0
- package/dist/esm/mixins/OxyServices.payment.js +155 -0
- package/dist/esm/mixins/OxyServices.privacy.js +196 -0
- package/dist/esm/mixins/OxyServices.reputation.js +286 -0
- package/dist/esm/mixins/OxyServices.security.js +86 -0
- package/dist/esm/mixins/OxyServices.store.js +263 -0
- package/dist/esm/mixins/OxyServices.topics.js +134 -0
- package/dist/esm/mixins/OxyServices.user.js +899 -0
- package/dist/esm/mixins/OxyServices.utility.js +1095 -0
- package/dist/esm/mixins/index.js +132 -0
- package/dist/esm/mixins/mixinHelpers.js +48 -0
- package/dist/esm/models/Topic.js +13 -0
- package/dist/esm/models/interfaces.js +17 -0
- package/dist/esm/models/session.js +1 -0
- package/dist/esm/server/auth.js +154 -0
- package/dist/esm/server/capabilityTicket.js +183 -0
- package/dist/esm/server/cors.js +220 -0
- package/dist/esm/server/index.js +47 -0
- package/dist/esm/server/rateLimit.js +201 -0
- package/dist/esm/server/safeFetch.js +447 -0
- package/dist/esm/server/securityHeaders.js +364 -0
- package/dist/esm/server/userInvalidation.js +152 -0
- package/dist/esm/server/verifySecret.js +47 -0
- package/dist/esm/session/SessionClient.js +861 -0
- package/dist/esm/session/accountDelegationAccess.js +45 -0
- package/dist/esm/session/accountDialogController.js +1126 -0
- package/dist/esm/session/accountSwitchTargets.js +77 -0
- package/dist/esm/session/authStateStore.js +398 -0
- package/dist/esm/session/createSessionClient.js +29 -0
- package/dist/esm/session/deviceDirectory.js +135 -0
- package/dist/esm/session/deviceSwitcherRows.js +72 -0
- package/dist/esm/session/identityPin.js +249 -0
- package/dist/esm/session/identitySession.js +131 -0
- package/dist/esm/session/projectSessionState.js +114 -0
- package/dist/esm/session/refresh.js +390 -0
- package/dist/esm/session/sessionClientHost.js +31 -0
- package/dist/esm/session/sharedDeviceCredential.js +239 -0
- package/dist/esm/session/socketLoader.js +19 -0
- package/dist/esm/shared/utils/colorUtils.js +143 -0
- package/dist/esm/shared/utils/errorUtils.js +170 -0
- package/dist/esm/shared/utils/index.js +15 -0
- package/dist/esm/shared/utils/networkUtils.js +173 -0
- package/dist/esm/shared/utils/themeUtils.js +98 -0
- package/dist/esm/utils/accountCacheSweep.js +75 -0
- package/dist/esm/utils/accountUtils.js +131 -0
- package/dist/esm/utils/activityId.js +2 -0
- package/dist/esm/utils/apiUtils.js +84 -0
- package/dist/esm/utils/asyncUtils.js +207 -0
- package/dist/esm/utils/authHelpers.js +111 -0
- package/dist/esm/utils/authWebUrl.js +16 -0
- package/dist/esm/utils/avatarUtils.js +26 -0
- package/dist/esm/utils/cache.js +227 -0
- package/dist/esm/utils/cacheKey.js +80 -0
- package/dist/esm/utils/coldBoot.js +119 -0
- package/dist/esm/utils/commonsApproval.js +27 -0
- package/dist/esm/utils/commonsDelivery.js +54 -0
- package/dist/esm/utils/deviceManager.js +170 -0
- package/dist/esm/utils/displayNamePolicyRanges.generated.js +57 -0
- package/dist/esm/utils/edgeRegion.js +2 -0
- package/dist/esm/utils/errorUtils.js +232 -0
- package/dist/esm/utils/identityCacheSweep.js +92 -0
- package/dist/esm/utils/languageUtils.js +212 -0
- package/dist/esm/utils/oauthPkce.js +297 -0
- package/dist/esm/utils/officialOrigins.js +59 -0
- package/dist/esm/utils/oxyServiceEnvironment.js +16 -0
- package/dist/esm/utils/platform.js +110 -0
- package/dist/esm/utils/profileLinks.js +60 -0
- package/dist/esm/utils/redactUrl.js +26 -0
- package/dist/esm/utils/registrableApex.js +42 -0
- package/dist/esm/utils/requestUtils.js +203 -0
- package/dist/esm/utils/sessionUtils.js +171 -0
- package/dist/esm/utils/textNormalization.js +154 -0
- package/dist/esm/utils/userHandle.js +33 -0
- package/dist/esm/utils/userIdentity.js +45 -0
- package/dist/esm/utils/validationUtils.js +350 -0
- package/dist/esm/utils/webauthnOrigin.js +48 -0
- package/dist/types/.tsbuildinfo +1 -0
- package/dist/types/HttpService.d.ts +413 -0
- package/dist/types/OxyServices.base.d.ts +187 -0
- package/dist/types/OxyServices.d.ts +139 -0
- package/dist/types/OxyServices.errors.d.ts +84 -0
- package/dist/types/boot/sessionColdBoot.d.ts +140 -0
- package/dist/types/constants/version.d.ts +13 -0
- package/dist/types/crypto/aead.d.ts +56 -0
- package/dist/types/crypto/ecdh.d.ts +29 -0
- package/dist/types/crypto/identityMarker.d.ts +94 -0
- package/dist/types/crypto/kdf.d.ts +25 -0
- package/dist/types/crypto/keyManager.d.ts +582 -0
- package/dist/types/crypto/polyfill.d.ts +25 -0
- package/dist/types/crypto/recoveryPhrase.d.ts +173 -0
- package/dist/types/crypto/signatureService.d.ts +136 -0
- package/dist/types/i18n/accountCategoryLabels.d.ts +34 -0
- package/dist/types/i18n/accountRoleLabels.d.ts +10 -0
- package/dist/types/i18n/index.d.ts +3 -0
- package/dist/types/i18n/reputationCategoryLabels.d.ts +10 -0
- package/dist/types/i18n/trustTierLabels.d.ts +9 -0
- package/dist/types/index.d.ts +145 -0
- package/dist/types/inference/OxyInferenceClient.d.ts +342 -0
- package/dist/types/logger/index.d.ts +104 -0
- package/dist/types/mixins/OxyServices.accounts.d.ts +868 -0
- package/dist/types/mixins/OxyServices.analytics.d.ts +72 -0
- package/dist/types/mixins/OxyServices.appData.d.ts +108 -0
- package/dist/types/mixins/OxyServices.assets.d.ts +329 -0
- package/dist/types/mixins/OxyServices.auth.d.ts +908 -0
- package/dist/types/mixins/OxyServices.chains.d.ts +156 -0
- package/dist/types/mixins/OxyServices.civic.d.ts +510 -0
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +169 -0
- package/dist/types/mixins/OxyServices.contacts.d.ts +100 -0
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +185 -0
- package/dist/types/mixins/OxyServices.deviceTransfer.d.ts +149 -0
- package/dist/types/mixins/OxyServices.devices.d.ts +103 -0
- package/dist/types/mixins/OxyServices.features.d.ts +250 -0
- package/dist/types/mixins/OxyServices.followGraph.d.ts +223 -0
- package/dist/types/mixins/OxyServices.identity.d.ts +351 -0
- package/dist/types/mixins/OxyServices.identityBackup.d.ts +129 -0
- package/dist/types/mixins/OxyServices.inference.d.ts +95 -0
- package/dist/types/mixins/OxyServices.language.d.ts +87 -0
- package/dist/types/mixins/OxyServices.links.d.ts +104 -0
- package/dist/types/mixins/OxyServices.location.d.ts +70 -0
- package/dist/types/mixins/OxyServices.nodes.d.ts +198 -0
- package/dist/types/mixins/OxyServices.notifications.d.ts +143 -0
- package/dist/types/mixins/OxyServices.payment.d.ts +117 -0
- package/dist/types/mixins/OxyServices.privacy.d.ts +146 -0
- package/dist/types/mixins/OxyServices.reputation.d.ts +202 -0
- package/dist/types/mixins/OxyServices.security.d.ts +84 -0
- package/dist/types/mixins/OxyServices.store.d.ts +334 -0
- package/dist/types/mixins/OxyServices.topics.d.ts +110 -0
- package/dist/types/mixins/OxyServices.user.d.ts +558 -0
- package/dist/types/mixins/OxyServices.utility.d.ts +393 -0
- package/dist/types/mixins/index.d.ts +87 -0
- package/dist/types/mixins/mixinHelpers.d.ts +31 -0
- package/dist/types/models/Topic.d.ts +42 -0
- package/dist/types/models/interfaces.d.ts +675 -0
- package/dist/types/models/session.d.ts +51 -0
- package/dist/types/server/auth.d.ts +130 -0
- package/dist/types/server/capabilityTicket.d.ts +41 -0
- package/dist/types/server/cors.d.ts +98 -0
- package/dist/types/server/index.d.ts +35 -0
- package/dist/types/server/rateLimit.d.ts +40 -0
- package/dist/types/server/safeFetch.d.ts +137 -0
- package/dist/types/server/securityHeaders.d.ts +221 -0
- package/dist/types/server/userInvalidation.d.ts +114 -0
- package/dist/types/server/verifySecret.d.ts +29 -0
- package/dist/types/session/SessionClient.d.ts +418 -0
- package/dist/types/session/accountDelegationAccess.d.ts +40 -0
- package/dist/types/session/accountDialogController.d.ts +648 -0
- package/dist/types/session/accountSwitchTargets.d.ts +70 -0
- package/dist/types/session/authStateStore.d.ts +153 -0
- package/dist/types/session/createSessionClient.d.ts +30 -0
- package/dist/types/session/deviceDirectory.d.ts +182 -0
- package/dist/types/session/deviceSwitcherRows.d.ts +92 -0
- package/dist/types/session/identityPin.d.ts +87 -0
- package/dist/types/session/identitySession.d.ts +105 -0
- package/dist/types/session/projectSessionState.d.ts +74 -0
- package/dist/types/session/refresh.d.ts +179 -0
- package/dist/types/session/sessionClientHost.d.ts +18 -0
- package/dist/types/session/sharedDeviceCredential.d.ts +202 -0
- package/dist/types/session/socketLoader.d.ts +11 -0
- package/dist/types/shared/utils/colorUtils.d.ts +104 -0
- package/dist/types/shared/utils/errorUtils.d.ts +97 -0
- package/dist/types/shared/utils/index.d.ts +13 -0
- package/dist/types/shared/utils/networkUtils.d.ts +139 -0
- package/dist/types/shared/utils/themeUtils.d.ts +90 -0
- package/dist/types/utils/accountCacheSweep.d.ts +75 -0
- package/dist/types/utils/accountUtils.d.ts +100 -0
- package/dist/types/utils/activityId.d.ts +2 -0
- package/dist/types/utils/apiUtils.d.ts +95 -0
- package/dist/types/utils/asyncUtils.d.ts +62 -0
- package/dist/types/utils/authHelpers.d.ts +58 -0
- package/dist/types/utils/authWebUrl.d.ts +16 -0
- package/dist/types/utils/avatarUtils.d.ts +16 -0
- package/dist/types/utils/cache.d.ts +130 -0
- package/dist/types/utils/cacheKey.d.ts +66 -0
- package/dist/types/utils/coldBoot.d.ts +131 -0
- package/dist/types/utils/commonsApproval.d.ts +13 -0
- package/dist/types/utils/commonsDelivery.d.ts +105 -0
- package/dist/types/utils/deviceManager.d.ts +65 -0
- package/dist/types/utils/displayNamePolicyRanges.generated.d.ts +57 -0
- package/dist/types/utils/edgeRegion.d.ts +2 -0
- package/dist/types/utils/errorUtils.d.ts +125 -0
- package/dist/types/utils/identityCacheSweep.d.ts +80 -0
- package/dist/types/utils/languageUtils.d.ts +100 -0
- package/dist/types/utils/oauthPkce.d.ts +157 -0
- package/dist/types/utils/officialOrigins.d.ts +13 -0
- package/dist/types/utils/oxyServiceEnvironment.d.ts +17 -0
- package/dist/types/utils/platform.d.ts +49 -0
- package/dist/types/utils/profileLinks.d.ts +44 -0
- package/dist/types/utils/redactUrl.d.ts +17 -0
- package/dist/types/utils/registrableApex.d.ts +27 -0
- package/dist/types/utils/requestUtils.d.ts +123 -0
- package/dist/types/utils/sessionUtils.d.ts +54 -0
- package/dist/types/utils/textNormalization.d.ts +103 -0
- package/dist/types/utils/userHandle.d.ts +26 -0
- package/dist/types/utils/userIdentity.d.ts +21 -0
- package/dist/types/utils/validationUtils.d.ts +268 -0
- package/dist/types/utils/webauthnOrigin.d.ts +32 -0
- package/package.json +168 -0
- package/src/HttpService.ts +1553 -0
- package/src/OxyServices.base.ts +478 -0
- package/src/OxyServices.errors.ts +122 -0
- package/src/OxyServices.ts +172 -0
- package/src/__tests__/authSocket.test.ts +96 -0
- package/src/__tests__/httpServiceActivityId.test.ts +49 -0
- package/src/__tests__/httpServiceAuthSelfAwait.test.ts +108 -0
- package/src/__tests__/httpServiceCache.test.ts +318 -0
- package/src/__tests__/httpServiceCsrf.test.ts +235 -0
- package/src/__tests__/httpServiceFormEncoded.test.ts +142 -0
- package/src/__tests__/httpServiceQueueDeadlock.test.ts +128 -0
- package/src/__tests__/httpServiceUnwrapEnvelope.test.ts +115 -0
- package/src/__tests__/inSessionRefresh.test.ts +260 -0
- package/src/__tests__/linkedClient.test.ts +370 -0
- package/src/__tests__/parseHttpErrorBody.test.ts +116 -0
- package/src/__tests__/serverValueImportsDeclared.test.ts +120 -0
- package/src/__tests__/userIdentity.test.ts +143 -0
- package/src/boot/__tests__/sessionColdBoot.identity.test.ts +393 -0
- package/src/boot/__tests__/sessionColdBoot.sharedDevice.test.ts +325 -0
- package/src/boot/__tests__/sessionColdBoot.test.ts +570 -0
- package/src/boot/sessionColdBoot.ts +529 -0
- package/src/constants/version.ts +15 -0
- package/src/crypto/__tests__/backupMaterial.test.ts +86 -0
- package/src/crypto/__tests__/cryptoPrimitives.test.ts +226 -0
- package/src/crypto/__tests__/identityMocks.ts +125 -0
- package/src/crypto/__tests__/keyManager.atomicity.test.ts +272 -0
- package/src/crypto/__tests__/keyManager.cacheSafety.test.ts +175 -0
- package/src/crypto/__tests__/keyManager.identityStatus.test.ts +217 -0
- package/src/crypto/__tests__/keyManager.recoveryLadder.test.ts +179 -0
- package/src/crypto/__tests__/keyManager.recoveryMnemonic.test.ts +138 -0
- package/src/crypto/__tests__/keyManager.storageMigration.test.ts +227 -0
- package/src/crypto/__tests__/keyManager.test.ts +329 -0
- package/src/crypto/__tests__/polyfill.test.ts +109 -0
- package/src/crypto/__tests__/recoveryPhrase.test.ts +61 -0
- package/src/crypto/__tests__/scopedSeed.test.ts +126 -0
- package/src/crypto/__tests__/signChallengeShared.test.ts +63 -0
- package/src/crypto/__tests__/signedRecord.test.ts +230 -0
- package/src/crypto/aead.ts +97 -0
- package/src/crypto/ecdh.ts +37 -0
- package/src/crypto/identityMarker.ts +291 -0
- package/src/crypto/kdf.ts +43 -0
- package/src/crypto/keyManager.ts +2607 -0
- package/src/crypto/polyfill.ts +143 -0
- package/src/crypto/recoveryPhrase.ts +337 -0
- package/src/crypto/signatureService.ts +350 -0
- package/src/i18n/__tests__/accountCategoryLabels.test.ts +62 -0
- package/src/i18n/__tests__/accountRoleLabels.test.ts +54 -0
- package/src/i18n/__tests__/reputationCategoryLabels.test.ts +56 -0
- package/src/i18n/__tests__/trustTierLabels.test.ts +47 -0
- package/src/i18n/accountCategoryLabels.ts +44 -0
- package/src/i18n/accountRoleLabels.ts +26 -0
- package/src/i18n/index.ts +88 -0
- package/src/i18n/locales/ar-SA.json +282 -0
- package/src/i18n/locales/ca-ES.json +282 -0
- package/src/i18n/locales/de-DE.json +282 -0
- package/src/i18n/locales/en-US.json +2161 -0
- package/src/i18n/locales/es-ES.json +2161 -0
- package/src/i18n/locales/fr-FR.json +282 -0
- package/src/i18n/locales/it-IT.json +282 -0
- package/src/i18n/locales/ja-JP.json +282 -0
- package/src/i18n/locales/ko-KR.json +282 -0
- package/src/i18n/locales/pt-PT.json +282 -0
- package/src/i18n/locales/zh-CN.json +282 -0
- package/src/i18n/reputationCategoryLabels.ts +20 -0
- package/src/i18n/trustTierLabels.ts +18 -0
- package/src/index.ts +881 -0
- package/src/inference/OxyInferenceClient.ts +888 -0
- package/src/inference/__tests__/OxyInferenceClient.test.ts +834 -0
- package/src/logger/__tests__/logger.test.ts +207 -0
- package/src/logger/index.ts +217 -0
- package/src/mixins/OxyServices.accounts.ts +1330 -0
- package/src/mixins/OxyServices.analytics.ts +53 -0
- package/src/mixins/OxyServices.appData.ts +158 -0
- package/src/mixins/OxyServices.assets.ts +861 -0
- package/src/mixins/OxyServices.auth.ts +1858 -0
- package/src/mixins/OxyServices.chains.ts +134 -0
- package/src/mixins/OxyServices.civic.ts +945 -0
- package/src/mixins/OxyServices.connectedApps.ts +174 -0
- package/src/mixins/OxyServices.contacts.ts +73 -0
- package/src/mixins/OxyServices.deviceBoot.ts +210 -0
- package/src/mixins/OxyServices.deviceTransfer.ts +393 -0
- package/src/mixins/OxyServices.devices.ts +120 -0
- package/src/mixins/OxyServices.features.ts +454 -0
- package/src/mixins/OxyServices.followGraph.ts +293 -0
- package/src/mixins/OxyServices.identity.ts +705 -0
- package/src/mixins/OxyServices.identityBackup.ts +250 -0
- package/src/mixins/OxyServices.inference.ts +57 -0
- package/src/mixins/OxyServices.language.ts +144 -0
- package/src/mixins/OxyServices.links.ts +107 -0
- package/src/mixins/OxyServices.location.ts +46 -0
- package/src/mixins/OxyServices.nodes.ts +337 -0
- package/src/mixins/OxyServices.notifications.ts +142 -0
- package/src/mixins/OxyServices.payment.ts +163 -0
- package/src/mixins/OxyServices.privacy.ts +219 -0
- package/src/mixins/OxyServices.reputation.ts +436 -0
- package/src/mixins/OxyServices.security.ts +110 -0
- package/src/mixins/OxyServices.store.ts +585 -0
- package/src/mixins/OxyServices.topics.ts +169 -0
- package/src/mixins/OxyServices.user.ts +1137 -0
- package/src/mixins/OxyServices.utility.ts +1370 -0
- package/src/mixins/__tests__/OxyServices.civic.test.ts +1095 -0
- package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +124 -0
- package/src/mixins/__tests__/OxyServices.deviceTransfer.test.ts +271 -0
- package/src/mixins/__tests__/OxyServices.identity.test.ts +376 -0
- package/src/mixins/__tests__/OxyServices.links.test.ts +154 -0
- package/src/mixins/__tests__/OxyServices.nodes.test.ts +341 -0
- package/src/mixins/__tests__/OxyServices.rotateKey.test.ts +276 -0
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadata.test.ts +192 -0
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadataBySha.test.ts +135 -0
- package/src/mixins/__tests__/accounts.test.ts +727 -0
- package/src/mixins/__tests__/appData.test.ts +203 -0
- package/src/mixins/__tests__/assetCredentials.test.ts +47 -0
- package/src/mixins/__tests__/assetUpload.test.ts +191 -0
- package/src/mixins/__tests__/backgroundCredential.httpIntegration.test.ts +135 -0
- package/src/mixins/__tests__/chains.test.ts +113 -0
- package/src/mixins/__tests__/commonsSignIn.test.ts +1144 -0
- package/src/mixins/__tests__/connectedApps.test.ts +123 -0
- package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +113 -0
- package/src/mixins/__tests__/discoveryErrorHandling.test.ts +266 -0
- package/src/mixins/__tests__/followCacheInvalidation.test.ts +173 -0
- package/src/mixins/__tests__/followGraph.test.ts +147 -0
- package/src/mixins/__tests__/followGraphPagination.test.ts +271 -0
- package/src/mixins/__tests__/getFileDownloadUrl.test.ts +346 -0
- package/src/mixins/__tests__/getFollowStatuses.test.ts +95 -0
- package/src/mixins/__tests__/getUsersByIds.test.ts +149 -0
- package/src/mixins/__tests__/identityBackup.test.ts +315 -0
- package/src/mixins/__tests__/identityWriteCacheInvalidation.test.ts +407 -0
- package/src/mixins/__tests__/inferenceFactory.test.ts +58 -0
- package/src/mixins/__tests__/onTokensChanged.test.ts +129 -0
- package/src/mixins/__tests__/preSessionSkipAuth.test.ts +284 -0
- package/src/mixins/__tests__/privacyCacheInvalidation.test.ts +155 -0
- package/src/mixins/__tests__/reputation.test.ts +522 -0
- package/src/mixins/__tests__/serviceAuth.test.ts +832 -0
- package/src/mixins/__tests__/serviceTokenJwks.test.ts +208 -0
- package/src/mixins/__tests__/store.test.ts +304 -0
- package/src/mixins/__tests__/topics.test.ts +156 -0
- package/src/mixins/__tests__/userReadCacheBypass.test.ts +129 -0
- package/src/mixins/__tests__/userTokenAuth.test.ts +746 -0
- package/src/mixins/__tests__/verifyChallenge.test.ts +130 -0
- package/src/mixins/__tests__/verifyServiceActingAs.test.ts +167 -0
- package/src/mixins/__tests__/webauthnAuth.test.ts +205 -0
- package/src/mixins/index.ts +201 -0
- package/src/mixins/mixinHelpers.ts +69 -0
- package/src/models/Topic.ts +46 -0
- package/src/models/interfaces.ts +786 -0
- package/src/models/session.ts +55 -0
- package/src/server/__tests__/auth.test.ts +78 -0
- package/src/server/__tests__/capabilityTicket.test.ts +111 -0
- package/src/server/__tests__/cors.socket.test.ts +225 -0
- package/src/server/__tests__/cors.test.ts +158 -0
- package/src/server/__tests__/rateLimit.test.ts +257 -0
- package/src/server/__tests__/safeFetch.test.ts +232 -0
- package/src/server/__tests__/securityHeaders.test.ts +348 -0
- package/src/server/__tests__/serviceTokenAttribution.test.ts +396 -0
- package/src/server/__tests__/userInvalidation.test.ts +203 -0
- package/src/server/__tests__/verifySecret.test.ts +40 -0
- package/src/server/auth.ts +271 -0
- package/src/server/capabilityTicket.ts +258 -0
- package/src/server/cors.ts +277 -0
- package/src/server/index.ts +136 -0
- package/src/server/rateLimit.ts +313 -0
- package/src/server/safeFetch.ts +586 -0
- package/src/server/securityHeaders.ts +467 -0
- package/src/server/userInvalidation.ts +199 -0
- package/src/server/verifySecret.ts +52 -0
- package/src/session/SessionClient.ts +1001 -0
- package/src/session/__tests__/SessionClient.additive.test.ts +153 -0
- package/src/session/__tests__/SessionClient.broadcastChannel.test.ts +114 -0
- package/src/session/__tests__/SessionClient.diagnostics.test.ts +91 -0
- package/src/session/__tests__/SessionClient.directory.test.ts +688 -0
- package/src/session/__tests__/SessionClient.httpIntegration.test.ts +65 -0
- package/src/session/__tests__/SessionClient.identityPin.test.ts +175 -0
- package/src/session/__tests__/SessionClient.rest.test.ts +119 -0
- package/src/session/__tests__/SessionClient.serverEvents.test.ts +72 -0
- package/src/session/__tests__/SessionClient.socket.test.ts +202 -0
- package/src/session/__tests__/SessionClient.socketFactory.test.ts +81 -0
- package/src/session/__tests__/SessionClient.state.test.ts +78 -0
- package/src/session/__tests__/SessionClient.switchTokenOrder.test.ts +170 -0
- package/src/session/__tests__/accountDelegationAccess.test.ts +104 -0
- package/src/session/__tests__/accountDialogController.test.ts +1969 -0
- package/src/session/__tests__/accountDialogShape.test.ts +118 -0
- package/src/session/__tests__/accountSwitchTargets.test.ts +137 -0
- package/src/session/__tests__/authStateStore.test.ts +451 -0
- package/src/session/__tests__/deviceDirectory.test.ts +422 -0
- package/src/session/__tests__/deviceSwitcherRows.test.ts +223 -0
- package/src/session/__tests__/identityPin.test.ts +131 -0
- package/src/session/__tests__/identitySession.test.ts +194 -0
- package/src/session/__tests__/projectSessionState.test.ts +105 -0
- package/src/session/__tests__/refresh.identityPin.test.ts +307 -0
- package/src/session/__tests__/refresh.test.ts +443 -0
- package/src/session/__tests__/sessionIntegration.test.ts +209 -0
- package/src/session/__tests__/sharedDeviceCredential.test.ts +300 -0
- package/src/session/accountDelegationAccess.ts +72 -0
- package/src/session/accountDialogController.ts +1494 -0
- package/src/session/accountSwitchTargets.ts +93 -0
- package/src/session/authStateStore.ts +502 -0
- package/src/session/createSessionClient.ts +39 -0
- package/src/session/deviceDirectory.ts +269 -0
- package/src/session/deviceSwitcherRows.ts +145 -0
- package/src/session/identityPin.ts +310 -0
- package/src/session/identitySession.ts +206 -0
- package/src/session/projectSessionState.ts +137 -0
- package/src/session/refresh.ts +517 -0
- package/src/session/sessionClientHost.ts +39 -0
- package/src/session/sharedDeviceCredential.ts +349 -0
- package/src/session/socketLoader.ts +30 -0
- package/src/shared/utils/colorUtils.ts +155 -0
- package/src/shared/utils/errorUtils.ts +181 -0
- package/src/shared/utils/index.ts +59 -0
- package/src/shared/utils/networkUtils.ts +248 -0
- package/src/shared/utils/themeUtils.ts +115 -0
- package/src/types/buffer.d.ts +97 -0
- package/src/types/expo-crypto.d.ts +16 -0
- package/src/types/expo-secure-store.d.ts +17 -0
- package/src/utils/__tests__/accountUtils.test.ts +151 -0
- package/src/utils/__tests__/activityId.test.ts +45 -0
- package/src/utils/__tests__/asyncUtils.test.ts +187 -0
- package/src/utils/__tests__/authWebUrl.test.ts +15 -0
- package/src/utils/__tests__/cacheKey.test.ts +0 -0
- package/src/utils/__tests__/coldBoot.test.ts +496 -0
- package/src/utils/__tests__/commonsApproval.test.ts +60 -0
- package/src/utils/__tests__/identityCacheSweep.test.ts +151 -0
- package/src/utils/__tests__/languageUtils.test.ts +219 -0
- package/src/utils/__tests__/oauthPkce.test.ts +272 -0
- package/src/utils/__tests__/officialOrigins.test.ts +31 -0
- package/src/utils/__tests__/oxyServiceEnvironment.test.ts +7 -0
- package/src/utils/__tests__/profileLinks.test.ts +180 -0
- package/src/utils/__tests__/redactUrl.test.ts +33 -0
- package/src/utils/__tests__/registrableApex.test.ts +62 -0
- package/src/utils/__tests__/textNormalization.test.ts +205 -0
- package/src/utils/__tests__/validationUtils.test.ts +703 -0
- package/src/utils/__tests__/webauthnOrigin.test.ts +83 -0
- package/src/utils/accountCacheSweep.ts +93 -0
- package/src/utils/accountUtils.ts +194 -0
- package/src/utils/activityId.ts +2 -0
- package/src/utils/apiUtils.ts +137 -0
- package/src/utils/asyncUtils.ts +280 -0
- package/src/utils/authHelpers.ts +148 -0
- package/src/utils/authWebUrl.ts +17 -0
- package/src/utils/avatarUtils.ts +39 -0
- package/src/utils/cache.ts +273 -0
- package/src/utils/cacheKey.ts +93 -0
- package/src/utils/coldBoot.ts +218 -0
- package/src/utils/commonsApproval.ts +39 -0
- package/src/utils/commonsDelivery.ts +132 -0
- package/src/utils/deviceManager.ts +203 -0
- package/src/utils/displayNamePolicyRanges.generated.ts +69 -0
- package/src/utils/edgeRegion.ts +2 -0
- package/src/utils/errorUtils.ts +352 -0
- package/src/utils/identityCacheSweep.ts +104 -0
- package/src/utils/languageUtils.ts +256 -0
- package/src/utils/oauthPkce.ts +392 -0
- package/src/utils/officialOrigins.ts +62 -0
- package/src/utils/oxyServiceEnvironment.ts +17 -0
- package/src/utils/platform.ts +139 -0
- package/src/utils/profileLinks.ts +91 -0
- package/src/utils/redactUrl.ts +28 -0
- package/src/utils/registrableApex.ts +41 -0
- package/src/utils/requestUtils.ts +237 -0
- package/src/utils/sessionUtils.ts +206 -0
- package/src/utils/textNormalization.ts +162 -0
- package/src/utils/userHandle.ts +49 -0
- package/src/utils/userIdentity.ts +60 -0
- package/src/utils/validationUtils.ts +390 -0
- package/src/utils/webauthnOrigin.ts +52 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified token refresh — THE single access-token re-mint for web + native.
|
|
3
|
+
*
|
|
4
|
+
* The access token is short-lived; there is no refresh token. To keep a session
|
|
5
|
+
* alive past the access token's TTL the client re-mints via the zero-cookie
|
|
6
|
+
* device transport:
|
|
7
|
+
*
|
|
8
|
+
* - `refreshPersistedSession` — arm 1 mints a fresh access token from the
|
|
9
|
+
* persisted `deviceId` + `deviceSecret` (`POST /session/device/token`),
|
|
10
|
+
* planting + persisting the rotated secret; arm 2 (native only) re-mints via
|
|
11
|
+
* the shared-keychain identity when there is no usable secret. It is used BOTH
|
|
12
|
+
* reactively (wrapped as the `AuthRefreshHandler` installed on `HttpService`)
|
|
13
|
+
* AND proactively (the scheduler below calls it).
|
|
14
|
+
* - `createAuthRefreshHandler` / `installAuthRefreshHandler` wire arm 1+2 into
|
|
15
|
+
* `HttpService.setAuthRefreshHandler`, keeping that layer's single-flight
|
|
16
|
+
* dedup + cooldown (this module does NOT reimplement them).
|
|
17
|
+
* - `startTokenRefreshScheduler` — a proactive scheduler decoupled from any
|
|
18
|
+
* React type: re-mints ~60s before `exp`, re-arms on token change + web
|
|
19
|
+
* tab-focus, `.unref?.()`s its timer in Node.
|
|
20
|
+
*
|
|
21
|
+
* Framework-free; no module-level mutable state.
|
|
22
|
+
*/
|
|
23
|
+
import type { DeviceSessionState, DeviceTokenMintResponse } from '@oxy.so/contracts';
|
|
24
|
+
import type { OxyServices } from '../OxyServices';
|
|
25
|
+
import type { AuthRefreshHandler, AuthRefreshReason } from '../HttpService';
|
|
26
|
+
import type { AuthStateStore, PersistedAuthState } from './authStateStore';
|
|
27
|
+
import type { IdentityPin } from './identityPin';
|
|
28
|
+
import { establishIdentitySession, resolveIdentityPin, type IdentityBinding } from './identitySession';
|
|
29
|
+
import { isNative } from '../utils/platform';
|
|
30
|
+
import { extractErrorStatus } from '../utils/errorUtils';
|
|
31
|
+
import { logger } from '../logger';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Lead time (ms) before access-token expiry at which the proactive scheduler
|
|
35
|
+
* re-mints. Mirrors `HttpService`'s per-request `TOKEN_REFRESH_LEAD_SECONDS`
|
|
36
|
+
* (60s) so the scheduled re-mint and the request-time preflight use the same
|
|
37
|
+
* window — the scheduler just fires it during idle/background.
|
|
38
|
+
*/
|
|
39
|
+
export const TOKEN_REFRESH_LEAD_MS = 60_000;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Max `setTimeout` delay (2^31 − 1 ms, ~24.8 days). A larger delay overflows
|
|
43
|
+
* the int32 timer field and fires IMMEDIATELY — with a long-TTL token that
|
|
44
|
+
* turns the reschedule-on-finish loop into a tight busy refresh. Clamp to it.
|
|
45
|
+
*/
|
|
46
|
+
const MAX_TIMEOUT_DELAY_MS = 2_147_483_647;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Floor (ms) on ANY scheduled delay. An already-expired / in-lead-window token
|
|
50
|
+
* computes a non-positive `exp − now − lead`; without this floor that becomes
|
|
51
|
+
* `setTimeout(…, 0)`, and a FAILING re-mint (offline / server error) would
|
|
52
|
+
* re-arm at 0 in the finally block → a tight 100%-CPU busy loop. The floor
|
|
53
|
+
* guarantees every re-arm yields the event loop.
|
|
54
|
+
*/
|
|
55
|
+
const MIN_SCHEDULE_DELAY_MS = 1_000;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Backoff schedule (ms) applied when a scheduled re-mint FAILS: first retry
|
|
59
|
+
* after {@link MIN_FAILURE_BACKOFF_MS}, doubling up to {@link MAX_FAILURE_BACKOFF_MS}.
|
|
60
|
+
* Reset to 0 on any success or token change. This is what converts the former
|
|
61
|
+
* zero-delay failure loop into a bounded, backing-off retry.
|
|
62
|
+
*/
|
|
63
|
+
const MIN_FAILURE_BACKOFF_MS = 5_000;
|
|
64
|
+
const MAX_FAILURE_BACKOFF_MS = 5 * 60_000;
|
|
65
|
+
|
|
66
|
+
export interface RefreshDeps {
|
|
67
|
+
oxy: OxyServices;
|
|
68
|
+
store: AuthStateStore;
|
|
69
|
+
/**
|
|
70
|
+
* Whether to fall back to the native shared-keychain re-mint (arm 2) when the
|
|
71
|
+
* persisted secret is absent / rejected. Defaults to `isNative()` — web has no
|
|
72
|
+
* shared keychain. Exposed for tests. IGNORED when {@link identity} is set: an
|
|
73
|
+
* identity-bound client must never adopt the CROSS-APP shared slot, which may
|
|
74
|
+
* hold a different identity than this device's primary key.
|
|
75
|
+
*/
|
|
76
|
+
allowSharedKeyFallback?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Identity-bound (pinned) mode. When present, every re-mint targets the
|
|
79
|
+
* PINNED account — resolved fresh from the pin store on each call, since a
|
|
80
|
+
* re-established session can move it — instead of the device's active
|
|
81
|
+
* account, and arm 2 becomes the PRIMARY-key identity sign-in rather than the
|
|
82
|
+
* shared-keychain one.
|
|
83
|
+
*/
|
|
84
|
+
identity?: IdentityBinding;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The outcome of ONE device-secret mint attempt (arm 1). Discriminated so both
|
|
89
|
+
* the re-mint handler and the cold boot can react per the transport contract
|
|
90
|
+
* without re-classifying the raw error:
|
|
91
|
+
* - `ok` — minted, persisted `nextDeviceSecret`, planted the token.
|
|
92
|
+
* - `no-secret` — the store holds no `deviceId` + `deviceSecret` to mint from.
|
|
93
|
+
* - `invalid-secret` — 401 `invalid_device_secret`: the presented secret
|
|
94
|
+
* no longer matches the server's stored hash.
|
|
95
|
+
* - `no-session` — 401 `no_active_session`: the device is known but has no live
|
|
96
|
+
* session (authoritative signed-out).
|
|
97
|
+
* - `account-not-on-device` — 401 `account_not_on_device` for a PINNED mint: the
|
|
98
|
+
* pinned account is not (or no longer) a live account of this device session.
|
|
99
|
+
* The device secret is FINE — it is the identity binding that went stale, so
|
|
100
|
+
* the caller must re-establish from the local key, never drop the credential.
|
|
101
|
+
* - `transient` — network / 5xx; keep the secret, a later attempt can succeed.
|
|
102
|
+
* - `persist-failed` — the mint succeeded but `nextDeviceSecret` could NOT be
|
|
103
|
+
* durably persisted. The token is deliberately NOT planted: advertising a
|
|
104
|
+
* healthy session on a secret that will not survive a reload is exactly the
|
|
105
|
+
* divergence that logs users out.
|
|
106
|
+
*/
|
|
107
|
+
export type DeviceSecretMintOutcome =
|
|
108
|
+
| { status: 'ok'; token: string; sessionId: string; userId: string; state: DeviceSessionState }
|
|
109
|
+
| { status: 'no-secret' }
|
|
110
|
+
| { status: 'invalid-secret' }
|
|
111
|
+
| { status: 'no-session' }
|
|
112
|
+
| { status: 'account-not-on-device' }
|
|
113
|
+
| { status: 'transient' }
|
|
114
|
+
| { status: 'persist-failed' };
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Arm 1 — the device-secret mint, run under the owning client's PROCESS-WIDE
|
|
118
|
+
* single-flight (`httpService.runSingleFlightDeviceSecretMint`).
|
|
119
|
+
*
|
|
120
|
+
* Concurrent lanes (cold boot, the proactive scheduler, a request-time preflight,
|
|
121
|
+
* a 401 retry, the socket token transport, or a tab-focus reconcile) must not
|
|
122
|
+
* each persist a different view of the mint response. Routing EVERY lane through
|
|
123
|
+
* this one single-flight makes concurrent callers await the SAME in-flight mint
|
|
124
|
+
* and all receive its result, so the durable store converges on one credential.
|
|
125
|
+
*
|
|
126
|
+
* On success it persists `nextDeviceSecret` (read-back-verified) BEFORE planting
|
|
127
|
+
* the access token; a failed durable persist yields `persist-failed` WITHOUT
|
|
128
|
+
* planting. This function performs NO store mutation on failure — the caller
|
|
129
|
+
* applies the drop/clear policy (which differs web vs native) from the returned
|
|
130
|
+
* status.
|
|
131
|
+
*
|
|
132
|
+
* `pin` makes the mint IDENTITY-BOUND: the request carries the pinned
|
|
133
|
+
* `accountId` (so the server mints that account's token without touching
|
|
134
|
+
* `activeAccountId`), and the persisted `sessionId`/`userId` are resolved from
|
|
135
|
+
* the PINNED account entry — never from `state.activeAccountId`, whose drift is
|
|
136
|
+
* exactly what the pin exists to stop.
|
|
137
|
+
*/
|
|
138
|
+
export async function refreshDeviceSecretArm(deps: {
|
|
139
|
+
oxy: OxyServices;
|
|
140
|
+
store: AuthStateStore;
|
|
141
|
+
/** The identity pin, when this client is identity-bound. */
|
|
142
|
+
pin?: IdentityPin | null;
|
|
143
|
+
}): Promise<DeviceSecretMintOutcome> {
|
|
144
|
+
const { oxy, store } = deps;
|
|
145
|
+
const pin = deps.pin ?? null;
|
|
146
|
+
return oxy.httpService.runSingleFlightDeviceSecretMint(async () => {
|
|
147
|
+
const persisted = await store.load();
|
|
148
|
+
if (!persisted?.deviceId || !persisted?.deviceSecret) {
|
|
149
|
+
return { status: 'no-secret' };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let mint: DeviceTokenMintResponse;
|
|
153
|
+
try {
|
|
154
|
+
// Unpinned callers pass NO third argument at all, so the account-mode call
|
|
155
|
+
// shape (and therefore the request body) is untouched by this feature.
|
|
156
|
+
mint = pin
|
|
157
|
+
? await oxy.mintFromDeviceSecret(persisted.deviceId, persisted.deviceSecret, {
|
|
158
|
+
accountId: pin.accountId,
|
|
159
|
+
})
|
|
160
|
+
: await oxy.mintFromDeviceSecret(persisted.deviceId, persisted.deviceSecret);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (extractErrorStatus(error) === 401) {
|
|
163
|
+
// Structural read (not `instanceof Error`): the thrown value can be a
|
|
164
|
+
// plain ApiError-shaped object or come from another realm.
|
|
165
|
+
const message = (error as { message?: unknown })?.message;
|
|
166
|
+
const body = typeof message === 'string' ? message : '';
|
|
167
|
+
// ONLY the server's explicit `invalid_device_secret` proves the presented
|
|
168
|
+
// secret is bad and may clear the durable device credential. `no_active_session`
|
|
169
|
+
// is an authoritative signed-out. ANY OTHER 401 — a middleware/CSRF/proxy 401,
|
|
170
|
+
// an ALB/starting-instance 401, a CORS error page, etc., all common during a
|
|
171
|
+
// deploy/restart window — is NOT proof the secret diverged: treat it as
|
|
172
|
+
// transient and KEEP the credential so a later attempt self-heals. Wiping the
|
|
173
|
+
// credential on an ambiguous 401 is what logged users out on every deploy,
|
|
174
|
+
// ecosystem-wide.
|
|
175
|
+
if (body.includes('invalid_device_secret')) return { status: 'invalid-secret' };
|
|
176
|
+
if (body.includes('no_active_session')) return { status: 'no-session' };
|
|
177
|
+
// A pinned mint whose account left the device set. The secret is intact —
|
|
178
|
+
// never classify this as a bad secret, or the caller would drop a healthy
|
|
179
|
+
// credential over a stale identity binding.
|
|
180
|
+
if (body.includes('account_not_on_device')) return { status: 'account-not-on-device' };
|
|
181
|
+
return { status: 'transient' };
|
|
182
|
+
}
|
|
183
|
+
return { status: 'transient' };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// The account this session is BOUND to: the pinned one when identity-bound
|
|
187
|
+
// (the server already minted for it), else the device's active account.
|
|
188
|
+
const boundAccountId = pin ? pin.accountId : mint.state.activeAccountId;
|
|
189
|
+
const bound = mint.state.accounts.find((a) => a.accountId === boundAccountId);
|
|
190
|
+
const next: PersistedAuthState = {
|
|
191
|
+
...persisted,
|
|
192
|
+
deviceId: mint.state.deviceId,
|
|
193
|
+
deviceSecret: mint.nextDeviceSecret,
|
|
194
|
+
accessToken: mint.accessToken,
|
|
195
|
+
expiresAt: mint.expiresAt,
|
|
196
|
+
...(bound ? { sessionId: bound.sessionId, userId: bound.accountId } : {}),
|
|
197
|
+
};
|
|
198
|
+
// Persist nextDeviceSecret (read-back-verified) BEFORE planting the token.
|
|
199
|
+
// A failed durable persist must NOT plant.
|
|
200
|
+
const persistedOk = await store.save(next);
|
|
201
|
+
if (!persistedOk) {
|
|
202
|
+
return { status: 'persist-failed' };
|
|
203
|
+
}
|
|
204
|
+
oxy.setTokens(mint.accessToken);
|
|
205
|
+
return {
|
|
206
|
+
status: 'ok',
|
|
207
|
+
token: mint.accessToken,
|
|
208
|
+
sessionId: next.sessionId,
|
|
209
|
+
userId: next.userId,
|
|
210
|
+
state: mint.state,
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Re-mint the persisted session and return the fresh access token, or `null`
|
|
217
|
+
* when no arm could produce one.
|
|
218
|
+
*
|
|
219
|
+
* Arm 1 (`POST /session/device/token`, via {@link refreshDeviceSecretArm}): mint
|
|
220
|
+
* from the persisted `deviceId` + `deviceSecret`. On a 401 the secret is diverged
|
|
221
|
+
* or the device has no live session: drop the secret so the mint lane stops (or
|
|
222
|
+
* clear the store on web, where there is no fallback), then fall to arm 2 on
|
|
223
|
+
* native. A transient error — or a durable-persist failure — leaves the store and
|
|
224
|
+
* returns `null` WITHOUT falling to shared-key (those are not bad-secret signals).
|
|
225
|
+
*
|
|
226
|
+
* Arm 2 (native shared-keychain): when the secret is absent or was just rejected,
|
|
227
|
+
* re-mint via `signInWithSharedIdentity` (which plants tokens). On success the
|
|
228
|
+
* recovered `{deviceId, deviceSecret, …}` is PERSISTED so the fast device-secret
|
|
229
|
+
* lane is repopulated (mirrors the cold boot's `shared-key-signin` step) — an
|
|
230
|
+
* in-session shared-key recovery must not leave the fast-lane credential empty.
|
|
231
|
+
*
|
|
232
|
+
* IDENTITY-BOUND clients (`deps.identity`) run a different arm 2: the
|
|
233
|
+
* shared-keychain lane is DISABLED (its cross-app slot may hold a different
|
|
234
|
+
* identity) and replaced by {@link establishIdentitySession}, which re-signs a
|
|
235
|
+
* challenge with the PRIMARY local key and rewrites the pin. Arm 1 is pinned.
|
|
236
|
+
*/
|
|
237
|
+
export async function refreshPersistedSession(deps: RefreshDeps): Promise<string | null> {
|
|
238
|
+
const { oxy, store } = deps;
|
|
239
|
+
const identity = deps.identity ?? null;
|
|
240
|
+
// The shared keychain is never an identity-bound client's recovery path.
|
|
241
|
+
const allowSharedKeyFallback = identity ? false : (deps.allowSharedKeyFallback ?? isNative());
|
|
242
|
+
// Resolved per call: a re-established identity session can move the pin, and a
|
|
243
|
+
// replaced/removed local key clears it (in which case arm 1 must NOT mint —
|
|
244
|
+
// an unpinned mint would adopt whatever account the device switched to).
|
|
245
|
+
const pin = identity ? await resolveIdentityPin(identity) : null;
|
|
246
|
+
if (identity && !pin) {
|
|
247
|
+
return recoverIdentitySession(oxy, store, identity);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const arm1 = await refreshDeviceSecretArm({ oxy, store, pin });
|
|
251
|
+
switch (arm1.status) {
|
|
252
|
+
case 'ok':
|
|
253
|
+
return arm1.token;
|
|
254
|
+
case 'transient':
|
|
255
|
+
logger.debug(
|
|
256
|
+
'Persisted deviceSecret mint failed (transient) — keeping store',
|
|
257
|
+
{ component: 'refresh', method: 'refreshPersistedSession' },
|
|
258
|
+
);
|
|
259
|
+
return null;
|
|
260
|
+
case 'persist-failed':
|
|
261
|
+
// The server rotated the secret but it did not durably persist. Do NOT fall
|
|
262
|
+
// to shared-key and do NOT plant — a later attempt re-mints (the process
|
|
263
|
+
// mirror still holds the rotated secret the server accepts) and can persist
|
|
264
|
+
// once storage recovers. Never advertise a session on an unsaved secret.
|
|
265
|
+
logger.error(
|
|
266
|
+
'Device-secret mint rotated the secret but it could not be durably persisted — refusing to plant (a later attempt re-mints)',
|
|
267
|
+
undefined,
|
|
268
|
+
{ component: 'refresh', method: 'refreshPersistedSession' },
|
|
269
|
+
);
|
|
270
|
+
return null;
|
|
271
|
+
case 'invalid-secret':
|
|
272
|
+
case 'no-session': {
|
|
273
|
+
// 401: secret diverged or no live session. When a key-based arm 2 can still
|
|
274
|
+
// recover (native shared key, or an identity-bound client's own primary
|
|
275
|
+
// key) drop ONLY the secret and keep the deviceId; otherwise (web) the
|
|
276
|
+
// session is over — clear the store.
|
|
277
|
+
const persisted = await store.load();
|
|
278
|
+
if (allowSharedKeyFallback || identity) {
|
|
279
|
+
if (persisted) {
|
|
280
|
+
await store.save({ ...persisted, deviceSecret: undefined });
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
await store.clear();
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
case 'account-not-on-device':
|
|
288
|
+
// The pinned account left this device's session set. The secret is healthy —
|
|
289
|
+
// leave the store untouched and let the identity arm re-establish.
|
|
290
|
+
logger.debug(
|
|
291
|
+
'Pinned device-secret mint rejected: the pinned account is no longer on this device — re-establishing from the identity key',
|
|
292
|
+
{ component: 'refresh', method: 'refreshPersistedSession' },
|
|
293
|
+
);
|
|
294
|
+
break;
|
|
295
|
+
case 'no-secret':
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (identity) {
|
|
300
|
+
return recoverIdentitySession(oxy, store, identity);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (allowSharedKeyFallback) {
|
|
304
|
+
try {
|
|
305
|
+
const session = await oxy.signInWithSharedIdentity();
|
|
306
|
+
if (session?.accessToken) {
|
|
307
|
+
// Repopulate the fast device-secret lane from the shared-key re-mint.
|
|
308
|
+
if (session.deviceId && session.deviceSecret) {
|
|
309
|
+
await store.save({
|
|
310
|
+
sessionId: session.sessionId,
|
|
311
|
+
userId: session.user.id,
|
|
312
|
+
deviceId: session.deviceId,
|
|
313
|
+
deviceSecret: session.deviceSecret,
|
|
314
|
+
accessToken: session.accessToken,
|
|
315
|
+
expiresAt: session.expiresAt,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return session.accessToken;
|
|
319
|
+
}
|
|
320
|
+
} catch (error) {
|
|
321
|
+
logger.debug(
|
|
322
|
+
'Shared-key re-mint fallback failed',
|
|
323
|
+
{ component: 'refresh', method: 'refreshPersistedSession' },
|
|
324
|
+
error,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Arm 2 for an IDENTITY-BOUND client: re-establish the session from the PRIMARY
|
|
334
|
+
* local key and rewrite the pin (`establishIdentitySession` plants the token and
|
|
335
|
+
* persists the device credential itself).
|
|
336
|
+
*
|
|
337
|
+
* Returns `null` — never throws — when there is no local identity, the verify
|
|
338
|
+
* yielded no token, or the exchange failed: the caller treats that as "could not
|
|
339
|
+
* refresh", exactly like the shared-key arm. A locked keychain therefore ends
|
|
340
|
+
* signed out rather than falling back to the device's active account.
|
|
341
|
+
*/
|
|
342
|
+
async function recoverIdentitySession(
|
|
343
|
+
oxy: OxyServices,
|
|
344
|
+
store: AuthStateStore,
|
|
345
|
+
binding: IdentityBinding,
|
|
346
|
+
): Promise<string | null> {
|
|
347
|
+
try {
|
|
348
|
+
const established = await establishIdentitySession({ oxy, store, binding });
|
|
349
|
+
return established?.session.accessToken ?? null;
|
|
350
|
+
} catch (error) {
|
|
351
|
+
logger.debug(
|
|
352
|
+
'Identity-key re-sign-in failed',
|
|
353
|
+
{ component: 'refresh', method: 'recoverIdentitySession' },
|
|
354
|
+
error,
|
|
355
|
+
);
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Build the reactive `AuthRefreshHandler` (arm 1 + arm 2). Install it via
|
|
362
|
+
* {@link installAuthRefreshHandler} or directly on
|
|
363
|
+
* `oxy.httpService.setAuthRefreshHandler`. `HttpService` owns single-flight
|
|
364
|
+
* dedup + cooldown, so the timer, the request-time preflight, and a 401 all
|
|
365
|
+
* collapse to one network attempt.
|
|
366
|
+
*/
|
|
367
|
+
export function createAuthRefreshHandler(deps: RefreshDeps): AuthRefreshHandler {
|
|
368
|
+
return async (_reason: AuthRefreshReason): Promise<string | null> => {
|
|
369
|
+
return refreshPersistedSession(deps);
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Install the unified refresh handler on the owner client's `HttpService`.
|
|
375
|
+
* Returns a disposer that removes it.
|
|
376
|
+
*/
|
|
377
|
+
export function installAuthRefreshHandler(deps: RefreshDeps): () => void {
|
|
378
|
+
deps.oxy.httpService.setAuthRefreshHandler(createAuthRefreshHandler(deps));
|
|
379
|
+
return () => {
|
|
380
|
+
deps.oxy.httpService.setAuthRefreshHandler(null);
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Handle returned by {@link startTokenRefreshScheduler}; `dispose()` tears it down. */
|
|
385
|
+
export interface TokenRefreshSchedulerHandle {
|
|
386
|
+
dispose(): void;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Start the proactive re-mint scheduler against `oxy`.
|
|
391
|
+
*
|
|
392
|
+
* Schedules a single timer to fire {@link TOKEN_REFRESH_LEAD_MS} before the
|
|
393
|
+
* current access token's `exp`, calling
|
|
394
|
+
* `oxy.httpService.refreshAccessToken('preflight')` (which runs the installed
|
|
395
|
+
* handler; deduped + cooldown-guarded). After every attempt it reschedules
|
|
396
|
+
* from the possibly-rotated token. It also reschedules whenever the token
|
|
397
|
+
* changes (a sign-out that clears the token cancels the timer) and, on web
|
|
398
|
+
* tab-focus, re-mints immediately if already inside the lead window (a
|
|
399
|
+
* long-hidden tab throttles timers, so the token can be expired on return).
|
|
400
|
+
*
|
|
401
|
+
* No-ops cleanly when there is no token or an opaque/no-`exp` token — the
|
|
402
|
+
* reactive 401 path stays the only re-mint trigger in that case. The timer is
|
|
403
|
+
* `.unref?.()`-ed so it never keeps a Node/Jest event loop alive.
|
|
404
|
+
*/
|
|
405
|
+
export function startTokenRefreshScheduler(oxy: OxyServices): TokenRefreshSchedulerHandle {
|
|
406
|
+
let disposed = false;
|
|
407
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
408
|
+
// 0 = no active backoff; grows on consecutive failures, resets on success /
|
|
409
|
+
// token change. Keeps a failing re-mint from re-arming at zero delay.
|
|
410
|
+
let failureBackoffMs = 0;
|
|
411
|
+
|
|
412
|
+
const clearTimer = (): void => {
|
|
413
|
+
if (timer !== null) {
|
|
414
|
+
clearTimeout(timer);
|
|
415
|
+
timer = null;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
/** Arm the timer for `delayMs`, flooring at {@link MIN_SCHEDULE_DELAY_MS} and capping at the int32 max. */
|
|
420
|
+
const armTimer = (delayMs: number): void => {
|
|
421
|
+
clearTimer();
|
|
422
|
+
const clamped = Math.min(Math.max(delayMs, MIN_SCHEDULE_DELAY_MS), MAX_TIMEOUT_DELAY_MS);
|
|
423
|
+
timer = setTimeout(runRefresh, clamped);
|
|
424
|
+
// Never keep a Node/Jest event loop alive for a background re-mint timer.
|
|
425
|
+
timer.unref?.();
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
/** Schedule the next re-mint from the current token's expiry (the healthy path). */
|
|
429
|
+
const scheduleFromExpiry = (): void => {
|
|
430
|
+
clearTimer();
|
|
431
|
+
if (disposed || !oxy.getAccessToken()) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const expSeconds = oxy.getAccessTokenExpiry();
|
|
435
|
+
if (expSeconds === null) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
armTimer(expSeconds * 1000 - Date.now() - TOKEN_REFRESH_LEAD_MS);
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const runRefresh = (): void => {
|
|
442
|
+
// Clear any pending timer up front so an out-of-band trigger (focus) plus
|
|
443
|
+
// a fired timer can never double-run.
|
|
444
|
+
clearTimer();
|
|
445
|
+
void oxy.httpService.refreshAccessToken('preflight')
|
|
446
|
+
.then((token) => Boolean(token))
|
|
447
|
+
.catch(() => false)
|
|
448
|
+
.then((ok) => {
|
|
449
|
+
if (disposed) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (ok) {
|
|
453
|
+
// Success — drop any backoff and re-arm from the rotated token's exp.
|
|
454
|
+
failureBackoffMs = 0;
|
|
455
|
+
scheduleFromExpiry();
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
// Failure — back off (never re-arm at zero) and retry.
|
|
459
|
+
failureBackoffMs =
|
|
460
|
+
failureBackoffMs === 0
|
|
461
|
+
? MIN_FAILURE_BACKOFF_MS
|
|
462
|
+
: Math.min(failureBackoffMs * 2, MAX_FAILURE_BACKOFF_MS);
|
|
463
|
+
armTimer(failureBackoffMs);
|
|
464
|
+
});
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
/** Public (re)schedule entry: a fresh token / focus signal — drop backoff and arm from expiry. */
|
|
468
|
+
const schedule = (): void => {
|
|
469
|
+
failureBackoffMs = 0;
|
|
470
|
+
scheduleFromExpiry();
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
const onFocus = (): void => {
|
|
474
|
+
if (disposed || !oxy.getAccessToken()) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
const expSeconds = oxy.getAccessTokenExpiry();
|
|
478
|
+
if (expSeconds === null) {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const remainingMs = expSeconds * 1000 - Date.now();
|
|
482
|
+
if (remainingMs <= TOKEN_REFRESH_LEAD_MS) {
|
|
483
|
+
runRefresh();
|
|
484
|
+
} else {
|
|
485
|
+
schedule();
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
const unsubscribeTokens = oxy.onTokensChanged(() => {
|
|
490
|
+
if (!disposed) {
|
|
491
|
+
schedule();
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
let removeFocusListener: (() => void) | null = null;
|
|
496
|
+
if (typeof document !== 'undefined') {
|
|
497
|
+
const handler = (): void => {
|
|
498
|
+
if (document.visibilityState === 'visible') {
|
|
499
|
+
onFocus();
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
document.addEventListener('visibilitychange', handler);
|
|
503
|
+
removeFocusListener = () => document.removeEventListener('visibilitychange', handler);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
schedule();
|
|
507
|
+
|
|
508
|
+
return {
|
|
509
|
+
dispose(): void {
|
|
510
|
+
disposed = true;
|
|
511
|
+
clearTimer();
|
|
512
|
+
unsubscribeTokens();
|
|
513
|
+
removeFocusListener?.();
|
|
514
|
+
removeFocusListener = null;
|
|
515
|
+
},
|
|
516
|
+
};
|
|
517
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { OxyServices } from '../OxyServices';
|
|
2
|
+
import type { DeviceCredential, SessionClientHost } from './SessionClient';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Thin `SessionClientHost` adapter over an `OxyServices` instance.
|
|
6
|
+
*
|
|
7
|
+
* `SessionClient` is host-agnostic: it only needs a REST + token surface.
|
|
8
|
+
* `OxyServices` already exposes all of that except `getCurrentAccountId`,
|
|
9
|
+
* which has no direct equivalent — the adapter holds a mutable ref set by
|
|
10
|
+
* the caller (`OxyContext` in `@oxy.so/services`) via `setCurrentAccountId`.
|
|
11
|
+
*
|
|
12
|
+
* Shared here (rather than duplicated per consumer) because it is entirely
|
|
13
|
+
* platform-agnostic: every method it calls exists identically on
|
|
14
|
+
* `OxyServices` regardless of host (web, Expo/RN, Node).
|
|
15
|
+
*/
|
|
16
|
+
export function createSessionClientHost(
|
|
17
|
+
oxyServices: OxyServices,
|
|
18
|
+
): SessionClientHost & {
|
|
19
|
+
setCurrentAccountId(id: string | null): void;
|
|
20
|
+
setDeviceCredential(credential: DeviceCredential | null): void;
|
|
21
|
+
} {
|
|
22
|
+
let currentAccountId: string | null = null;
|
|
23
|
+
let deviceCredential: DeviceCredential | null = null;
|
|
24
|
+
return {
|
|
25
|
+
makeRequest: (method, url, data, options) => oxyServices.makeRequest(method, url, data, options),
|
|
26
|
+
getBaseURL: () => oxyServices.getBaseURL(),
|
|
27
|
+
getAccessToken: () => oxyServices.getAccessToken(),
|
|
28
|
+
getDeviceCredential: () => deviceCredential,
|
|
29
|
+
onTokensChanged: (listener) => oxyServices.onTokensChanged(listener),
|
|
30
|
+
setTokens: (accessToken) => oxyServices.setTokens(accessToken),
|
|
31
|
+
getCurrentAccountId: () => currentAccountId,
|
|
32
|
+
setCurrentAccountId: (id) => {
|
|
33
|
+
currentAccountId = id;
|
|
34
|
+
},
|
|
35
|
+
setDeviceCredential: (credential) => {
|
|
36
|
+
deviceCredential = credential;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|