@oxy.so/core 1.18.1 → 3.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/README.md +13 -7
- package/dist/cjs/HttpService.js +159 -111
- package/dist/cjs/OxyServices.errors.js +48 -1
- package/dist/cjs/OxyServices.js +263 -60
- package/dist/cjs/api/accounts.js +231 -0
- package/dist/cjs/api/agency.js +102 -0
- package/dist/cjs/api/appData.js +45 -0
- package/dist/cjs/api/apps.js +197 -0
- package/dist/cjs/api/assets.js +329 -0
- package/dist/cjs/api/auth.js +900 -0
- package/dist/cjs/api/billing.js +44 -0
- package/dist/cjs/api/civic.js +289 -0
- package/dist/cjs/api/contacts.js +16 -0
- package/dist/cjs/api/devices.js +351 -0
- package/dist/cjs/api/follows.js +240 -0
- package/dist/cjs/api/identity.js +569 -0
- package/dist/cjs/api/linkedAccounts.js +48 -0
- package/dist/cjs/api/nodes.js +75 -0
- package/dist/cjs/api/notifications.js +75 -0
- package/dist/cjs/api/privacy.js +105 -0
- package/dist/cjs/api/reputation.js +74 -0
- package/dist/cjs/api/session.js +177 -0
- package/dist/cjs/api/store.js +199 -0
- package/dist/cjs/api/topics.js +66 -0
- package/dist/cjs/api/users.js +309 -0
- package/dist/cjs/boot/sessionColdBoot.js +4 -4
- package/dist/cjs/civic/index.js +16 -0
- package/dist/cjs/civic/payloads.js +156 -0
- package/dist/cjs/client/context.js +2 -0
- package/dist/cjs/crypto/identityLink.js +5 -5
- package/dist/cjs/crypto/index.js +44 -0
- package/dist/cjs/crypto/internal.js +37 -0
- package/dist/cjs/crypto/keyManager.js +2 -2
- package/dist/cjs/crypto/polyfill.js +9 -80
- package/dist/cjs/crypto/recoveryPhrase.js +1 -0
- package/dist/cjs/crypto/registrationPow.js +1 -1
- package/dist/cjs/crypto/signatureService.js +1 -0
- package/dist/cjs/i18n/accountCategoryLabels.js +3 -3
- package/dist/cjs/i18n/accountRoleLabels.js +7 -7
- package/dist/cjs/i18n/index.js +130 -52
- package/dist/cjs/i18n/locales/{ar-SA.json → ar-SA.js} +134 -52
- package/dist/cjs/i18n/locales/{ca-ES.json → ca-ES.js} +134 -52
- package/dist/{esm/i18n/locales/de-DE.json → cjs/i18n/locales/de-DE.js} +136 -54
- package/dist/{esm/i18n/locales/en-US.json → cjs/i18n/locales/en-US.js} +163 -245
- package/dist/{esm/i18n/locales/es-ES.json → cjs/i18n/locales/es-ES.js} +163 -245
- package/dist/cjs/i18n/locales/{fr-FR.json → fr-FR.js} +134 -52
- package/dist/cjs/i18n/locales/{it-IT.json → it-IT.js} +134 -52
- package/dist/{esm/i18n/locales/ja-JP.json → cjs/i18n/locales/ja-JP.js} +134 -52
- package/dist/cjs/i18n/locales/{ko-KR.json → ko-KR.js} +134 -52
- package/dist/{esm/i18n/locales/pt-PT.json → cjs/i18n/locales/pt-PT.js} +136 -54
- package/dist/{esm/i18n/locales/zh-CN.json → cjs/i18n/locales/zh-CN.js} +135 -53
- package/dist/cjs/i18n/reputationCategoryLabels.js +2 -2
- package/dist/cjs/i18n/trustTierLabels.js +2 -2
- package/dist/cjs/index.js +55 -263
- package/dist/cjs/inference/index.js +21 -0
- package/dist/cjs/server/OxyServer.js +521 -0
- package/dist/cjs/server/auth.js +2 -2
- package/dist/cjs/server/index.js +23 -6
- package/dist/cjs/server/middleware.js +1154 -0
- package/dist/cjs/server/namespaces.js +214 -0
- package/dist/cjs/server/rateLimit.js +2 -2
- package/dist/cjs/server/requesterAssertion.js +5 -5
- package/dist/cjs/server/securityHeaders.js +3 -3
- package/dist/cjs/server/traffic.js +7 -6
- package/dist/cjs/server/trafficNodeHttp.js +9 -3
- package/dist/cjs/server/userInvalidation.js +5 -5
- package/dist/cjs/session/accountDialogController.js +23 -23
- package/dist/cjs/session/authStateStore.js +2 -2
- package/dist/cjs/session/identitySession.js +3 -3
- package/dist/cjs/session/index.js +131 -0
- package/dist/cjs/session/refresh.js +37 -30
- package/dist/cjs/session/sessionClientHost.js +5 -5
- package/dist/cjs/session/sharedDeviceCredential.js +3 -2
- package/dist/cjs/shared/utils/networkUtils.js +2 -2
- package/dist/cjs/utils/accountCacheSweep.js +11 -15
- package/dist/cjs/utils/asyncUtils.js +22 -163
- package/dist/cjs/utils/authHelpers.js +2 -2
- package/dist/cjs/utils/authWebUrl.js +3 -4
- package/dist/cjs/utils/avatarUtils.js +2 -2
- package/dist/cjs/utils/cache.js +32 -2
- package/dist/cjs/utils/cacheKey.js +5 -10
- package/dist/cjs/utils/deviceManager.js +17 -16
- package/dist/cjs/utils/edgeRegion.js +2 -3
- package/dist/cjs/utils/identityCacheSweep.js +6 -10
- package/dist/cjs/utils/oxyServiceEnvironment.js +3 -7
- package/dist/cjs/utils/requestUtils.js +40 -33
- package/dist/cjs/utils/sessionUtils.js +0 -2
- package/dist/cjs/utils/tokenClaims.js +34 -0
- package/dist/esm/HttpService.js +160 -112
- package/dist/esm/OxyServices.errors.js +45 -0
- package/dist/esm/OxyServices.js +262 -57
- package/dist/esm/api/accounts.js +218 -0
- package/dist/esm/api/agency.js +95 -0
- package/dist/esm/api/appData.js +40 -0
- package/dist/esm/api/apps.js +191 -0
- package/dist/esm/api/assets.js +324 -0
- package/dist/esm/api/auth.js +858 -0
- package/dist/esm/api/billing.js +40 -0
- package/dist/esm/api/civic.js +250 -0
- package/dist/esm/api/contacts.js +12 -0
- package/dist/esm/api/devices.js +346 -0
- package/dist/esm/api/follows.js +236 -0
- package/dist/esm/api/identity.js +527 -0
- package/dist/esm/api/linkedAccounts.js +44 -0
- package/dist/esm/api/nodes.js +71 -0
- package/dist/esm/api/notifications.js +71 -0
- package/dist/esm/api/privacy.js +101 -0
- package/dist/esm/api/reputation.js +70 -0
- package/dist/esm/api/session.js +173 -0
- package/dist/esm/api/store.js +192 -0
- package/dist/esm/api/topics.js +62 -0
- package/dist/esm/api/users.js +272 -0
- package/dist/esm/boot/sessionColdBoot.js +4 -4
- package/dist/esm/civic/index.js +10 -0
- package/dist/esm/civic/payloads.js +118 -0
- package/dist/esm/client/context.js +1 -0
- package/dist/esm/crypto/identityLink.js +5 -5
- package/dist/esm/crypto/index.js +24 -0
- package/dist/esm/crypto/internal.js +19 -0
- package/dist/esm/crypto/keyManager.js +2 -2
- package/dist/esm/crypto/polyfill.js +10 -81
- package/dist/esm/crypto/recoveryPhrase.js +1 -0
- package/dist/esm/crypto/registrationPow.js +1 -1
- package/dist/esm/crypto/signatureService.js +1 -0
- package/dist/esm/i18n/accountCategoryLabels.js +2 -2
- package/dist/esm/i18n/accountRoleLabels.js +1 -1
- package/dist/esm/i18n/index.js +93 -52
- package/dist/esm/i18n/locales/{ar-SA.json → ar-SA.js} +132 -52
- package/dist/esm/i18n/locales/{ca-ES.json → ca-ES.js} +132 -52
- package/dist/{cjs/i18n/locales/de-DE.json → esm/i18n/locales/de-DE.js} +134 -54
- package/dist/{cjs/i18n/locales/en-US.json → esm/i18n/locales/en-US.js} +161 -245
- package/dist/{cjs/i18n/locales/es-ES.json → esm/i18n/locales/es-ES.js} +161 -245
- package/dist/esm/i18n/locales/{fr-FR.json → fr-FR.js} +132 -52
- package/dist/esm/i18n/locales/{it-IT.json → it-IT.js} +132 -52
- package/dist/{cjs/i18n/locales/ja-JP.json → esm/i18n/locales/ja-JP.js} +132 -52
- package/dist/esm/i18n/locales/{ko-KR.json → ko-KR.js} +132 -52
- package/dist/{cjs/i18n/locales/pt-PT.json → esm/i18n/locales/pt-PT.js} +134 -54
- package/dist/{cjs/i18n/locales/zh-CN.json → esm/i18n/locales/zh-CN.js} +133 -53
- package/dist/esm/i18n/reputationCategoryLabels.js +1 -1
- package/dist/esm/i18n/trustTierLabels.js +1 -1
- package/dist/esm/index.js +30 -166
- package/dist/esm/inference/index.js +13 -0
- package/dist/esm/server/OxyServer.js +516 -0
- package/dist/esm/server/auth.js +2 -2
- package/dist/esm/server/index.js +10 -5
- package/dist/esm/server/middleware.js +1147 -0
- package/dist/esm/server/namespaces.js +206 -0
- package/dist/esm/server/rateLimit.js +2 -2
- package/dist/esm/server/requesterAssertion.js +5 -5
- package/dist/esm/server/securityHeaders.js +3 -3
- package/dist/esm/server/traffic.js +7 -6
- package/dist/esm/server/trafficNodeHttp.js +9 -3
- package/dist/esm/server/userInvalidation.js +5 -5
- package/dist/esm/session/accountDialogController.js +23 -23
- package/dist/esm/session/authStateStore.js +2 -2
- package/dist/esm/session/identitySession.js +3 -3
- package/dist/esm/session/index.js +82 -0
- package/dist/esm/session/refresh.js +37 -30
- package/dist/esm/session/sessionClientHost.js +5 -5
- package/dist/esm/session/sharedDeviceCredential.js +3 -2
- package/dist/esm/shared/utils/networkUtils.js +2 -2
- package/dist/esm/utils/accountCacheSweep.js +11 -15
- package/dist/esm/utils/asyncUtils.js +22 -151
- package/dist/esm/utils/authHelpers.js +2 -2
- package/dist/esm/utils/authWebUrl.js +3 -4
- package/dist/esm/utils/avatarUtils.js +2 -2
- package/dist/esm/utils/cache.js +32 -2
- package/dist/esm/utils/cacheKey.js +5 -10
- package/dist/esm/utils/deviceManager.js +17 -16
- package/dist/esm/utils/edgeRegion.js +1 -2
- package/dist/esm/utils/identityCacheSweep.js +6 -10
- package/dist/esm/utils/oxyServiceEnvironment.js +3 -7
- package/dist/esm/utils/requestUtils.js +40 -33
- package/dist/esm/utils/sessionUtils.js +0 -2
- package/dist/esm/utils/tokenClaims.js +31 -0
- package/dist/types/HttpService.d.ts +26 -9
- package/dist/types/OxyServices.d.ts +160 -131
- package/dist/types/OxyServices.errors.d.ts +42 -0
- package/dist/types/api/accounts.d.ts +415 -0
- package/dist/types/api/agency.d.ts +135 -0
- package/dist/types/api/appData.d.ts +27 -0
- package/dist/types/api/apps.d.ts +433 -0
- package/dist/types/api/assets.d.ts +174 -0
- package/dist/types/api/auth.d.ts +766 -0
- package/dist/types/api/billing.d.ts +113 -0
- package/dist/types/api/civic.d.ts +203 -0
- package/dist/types/api/contacts.d.ts +31 -0
- package/{src/mixins/OxyServices.deviceBoot.ts → dist/types/api/devices.d.ts} +130 -110
- package/dist/types/api/follows.d.ts +236 -0
- package/dist/types/api/identity.d.ts +275 -0
- package/dist/types/api/linkedAccounts.d.ts +48 -0
- package/dist/types/api/nodes.d.ts +102 -0
- package/dist/types/api/notifications.d.ts +77 -0
- package/dist/types/api/privacy.d.ts +43 -0
- package/dist/types/api/reputation.d.ts +50 -0
- package/dist/types/api/session.d.ts +85 -0
- package/dist/types/api/store.d.ts +278 -0
- package/dist/types/api/topics.d.ts +34 -0
- package/dist/types/api/users.d.ts +134 -0
- package/dist/types/boot/sessionColdBoot.d.ts +1 -1
- package/dist/types/civic/index.d.ts +10 -0
- package/dist/types/civic/payloads.d.ts +83 -0
- package/dist/types/client/context.d.ts +33 -0
- package/dist/types/crypto/identityLink.d.ts +5 -5
- package/dist/types/crypto/index.d.ts +24 -0
- package/dist/types/crypto/internal.d.ts +19 -0
- package/dist/types/crypto/polyfill.d.ts +6 -9
- package/dist/types/crypto/registrationPow.d.ts +1 -1
- package/dist/types/i18n/accountCategoryLabels.d.ts +1 -1
- package/dist/types/i18n/accountRoleLabels.d.ts +1 -1
- package/dist/types/i18n/index.d.ts +20 -1
- package/dist/types/i18n/locales/ar-SA.d.ts +386 -0
- package/dist/types/i18n/locales/ca-ES.d.ts +386 -0
- package/dist/types/i18n/locales/de-DE.d.ts +386 -0
- package/dist/types/i18n/locales/en-US.d.ts +2034 -0
- package/dist/types/i18n/locales/es-ES.d.ts +2034 -0
- package/dist/types/i18n/locales/fr-FR.d.ts +386 -0
- package/dist/types/i18n/locales/it-IT.d.ts +386 -0
- package/dist/types/i18n/locales/ja-JP.d.ts +386 -0
- package/dist/types/i18n/locales/ko-KR.d.ts +386 -0
- package/dist/types/i18n/locales/pt-PT.d.ts +386 -0
- package/dist/types/i18n/locales/zh-CN.d.ts +386 -0
- package/dist/types/index.d.ts +46 -95
- package/dist/types/inference/index.d.ts +22 -0
- package/dist/types/models/interfaces.d.ts +1 -22
- package/dist/types/server/OxyServer.d.ts +183 -0
- package/dist/types/server/auth.d.ts +10 -7
- package/dist/types/server/index.d.ts +10 -4
- package/dist/types/server/middleware.d.ts +291 -0
- package/dist/types/server/namespaces.d.ts +98 -0
- package/dist/types/server/rateLimit.d.ts +7 -5
- package/dist/types/server/requesterAssertion.d.ts +14 -11
- package/dist/types/server/securityHeaders.d.ts +4 -5
- package/dist/types/server/userInvalidation.d.ts +10 -8
- package/dist/types/session/accountDelegationAccess.d.ts +1 -1
- package/dist/types/session/accountDialogController.d.ts +8 -8
- package/dist/types/session/accountSwitchTargets.d.ts +1 -1
- package/dist/types/session/authStateStore.d.ts +7 -6
- package/dist/types/session/index.d.ts +40 -0
- package/dist/types/utils/accountCacheSweep.d.ts +7 -10
- package/dist/types/utils/apiUtils.d.ts +3 -3
- package/dist/types/utils/asyncUtils.d.ts +11 -58
- package/dist/types/utils/authWebUrl.d.ts +3 -4
- package/dist/types/utils/avatarUtils.d.ts +5 -6
- package/dist/types/utils/cache.d.ts +11 -3
- package/dist/types/utils/commonsApproval.d.ts +1 -1
- package/dist/types/utils/edgeRegion.d.ts +1 -2
- package/dist/types/utils/identityCacheSweep.d.ts +6 -4
- package/dist/types/utils/oauthPkce.d.ts +2 -2
- package/dist/types/utils/oxyServiceEnvironment.d.ts +3 -7
- package/dist/types/utils/requestUtils.d.ts +18 -14
- package/dist/types/utils/tokenClaims.d.ts +9 -0
- package/package.json +68 -7
- package/src/HttpService.ts +166 -131
- package/src/OxyServices.errors.ts +73 -0
- package/src/OxyServices.ts +289 -164
- package/src/api/accounts.ts +579 -0
- package/src/api/agency.ts +277 -0
- package/src/api/appData.ts +63 -0
- package/src/api/apps.ts +596 -0
- package/src/api/assets.ts +416 -0
- package/src/api/auth.ts +1457 -0
- package/src/api/billing.ts +144 -0
- package/src/api/civic.ts +428 -0
- package/src/api/contacts.ts +41 -0
- package/src/api/devices.ts +438 -0
- package/src/api/follows.ts +414 -0
- package/src/api/identity.ts +727 -0
- package/src/api/linkedAccounts.ts +78 -0
- package/src/api/nodes.ts +169 -0
- package/src/api/notifications.ts +135 -0
- package/src/api/privacy.ts +120 -0
- package/src/api/reputation.ts +134 -0
- package/src/api/session.ts +210 -0
- package/src/api/store.ts +435 -0
- package/src/api/topics.ts +83 -0
- package/src/api/users.ts +357 -0
- package/src/boot/sessionColdBoot.ts +4 -4
- package/src/civic/index.ts +12 -0
- package/src/civic/payloads.ts +175 -0
- package/src/client/context.ts +34 -0
- package/src/crypto/identityLink.ts +5 -5
- package/src/crypto/index.ts +39 -0
- package/src/crypto/internal.ts +20 -0
- package/src/crypto/keyManager.ts +2 -2
- package/src/crypto/polyfill.ts +9 -89
- package/src/crypto/recoveryPhrase.ts +1 -0
- package/src/crypto/registrationPow.ts +1 -1
- package/src/crypto/signatureService.ts +1 -0
- package/src/i18n/accountCategoryLabels.ts +2 -2
- package/src/i18n/accountRoleLabels.ts +2 -2
- package/src/i18n/index.ts +105 -54
- package/src/i18n/locales/{ar-SA.json → ar-SA.ts} +132 -52
- package/src/i18n/locales/{ca-ES.json → ca-ES.ts} +132 -52
- package/{dist/cjs/i18n/locales/locales/de-DE.json → src/i18n/locales/de-DE.ts} +134 -54
- package/src/i18n/locales/{en-US.json → en-US.ts} +161 -245
- package/{dist/cjs/i18n/locales/locales/es-ES.json → src/i18n/locales/es-ES.ts} +161 -245
- package/src/i18n/locales/{fr-FR.json → fr-FR.ts} +132 -52
- package/src/i18n/locales/{it-IT.json → it-IT.ts} +132 -52
- package/{dist/cjs/i18n/locales/locales/ja-JP.json → src/i18n/locales/ja-JP.ts} +132 -52
- package/src/i18n/locales/{ko-KR.json → ko-KR.ts} +132 -52
- package/src/i18n/locales/{pt-PT.json → pt-PT.ts} +134 -54
- package/src/i18n/locales/{zh-CN.json → zh-CN.ts} +133 -53
- package/src/i18n/reputationCategoryLabels.ts +1 -1
- package/src/i18n/trustTierLabels.ts +1 -1
- package/src/index.ts +170 -501
- package/src/inference/index.ts +48 -0
- package/src/models/interfaces.ts +1 -22
- package/src/server/OxyServer.ts +637 -0
- package/src/server/auth.ts +12 -8
- package/src/server/index.ts +28 -5
- package/src/server/middleware.ts +1520 -0
- package/src/server/namespaces.ts +257 -0
- package/src/server/rateLimit.ts +10 -9
- package/src/server/requesterAssertion.ts +13 -10
- package/src/server/securityHeaders.ts +7 -8
- package/src/server/traffic.ts +6 -6
- package/src/server/trafficNodeHttp.ts +7 -3
- package/src/server/userInvalidation.ts +9 -9
- package/src/session/accountDelegationAccess.ts +1 -1
- package/src/session/accountDialogController.ts +24 -24
- package/src/session/accountSwitchTargets.ts +1 -1
- package/src/session/authStateStore.ts +9 -8
- package/src/session/identitySession.ts +3 -3
- package/src/session/index.ts +210 -0
- package/src/session/refresh.ts +36 -30
- package/src/session/sessionClientHost.ts +5 -5
- package/src/session/sharedDeviceCredential.ts +3 -2
- package/src/shared/utils/networkUtils.ts +2 -2
- package/src/utils/accountCacheSweep.ts +11 -15
- package/src/utils/apiUtils.ts +3 -3
- package/src/utils/asyncUtils.ts +38 -235
- package/src/utils/authHelpers.ts +2 -2
- package/src/utils/authWebUrl.ts +3 -4
- package/src/utils/avatarUtils.ts +4 -7
- package/src/utils/cache.ts +36 -5
- package/src/utils/cacheKey.ts +5 -9
- package/src/utils/commonsApproval.ts +1 -1
- package/src/utils/deviceManager.ts +17 -16
- package/src/utils/edgeRegion.ts +1 -2
- package/src/utils/identityCacheSweep.ts +7 -12
- package/src/utils/oauthPkce.ts +2 -2
- package/src/utils/oxyServiceEnvironment.ts +3 -7
- package/src/utils/requestUtils.ts +48 -44
- package/src/utils/sessionUtils.ts +0 -2
- package/src/utils/tokenClaims.ts +38 -0
- package/dist/cjs/.tsbuildinfo +0 -1
- package/dist/cjs/OxyServices.base.js +0 -392
- package/dist/cjs/i18n/locales/locales/ar-SA.json +0 -306
- package/dist/cjs/i18n/locales/locales/ca-ES.json +0 -306
- package/dist/cjs/i18n/locales/locales/en-US.json +0 -2127
- package/dist/cjs/i18n/locales/locales/fr-FR.json +0 -306
- package/dist/cjs/i18n/locales/locales/it-IT.json +0 -306
- package/dist/cjs/i18n/locales/locales/ko-KR.json +0 -306
- package/dist/cjs/i18n/locales/locales/pt-PT.json +0 -306
- package/dist/cjs/i18n/locales/locales/zh-CN.json +0 -306
- package/dist/cjs/mixins/OxyServices.accounts.js +0 -555
- package/dist/cjs/mixins/OxyServices.agency.js +0 -154
- package/dist/cjs/mixins/OxyServices.analytics.js +0 -49
- package/dist/cjs/mixins/OxyServices.appData.js +0 -108
- package/dist/cjs/mixins/OxyServices.assets.js +0 -854
- package/dist/cjs/mixins/OxyServices.auth.js +0 -1495
- package/dist/cjs/mixins/OxyServices.chains.js +0 -73
- package/dist/cjs/mixins/OxyServices.civic.js +0 -611
- package/dist/cjs/mixins/OxyServices.connectedApps.js +0 -95
- package/dist/cjs/mixins/OxyServices.contacts.js +0 -50
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +0 -191
- package/dist/cjs/mixins/OxyServices.devices.js +0 -116
- package/dist/cjs/mixins/OxyServices.features.js +0 -335
- package/dist/cjs/mixins/OxyServices.followGraph.js +0 -221
- package/dist/cjs/mixins/OxyServices.identity.js +0 -562
- package/dist/cjs/mixins/OxyServices.identityBackup.js +0 -172
- package/dist/cjs/mixins/OxyServices.inference.js +0 -59
- package/dist/cjs/mixins/OxyServices.language.js +0 -125
- package/dist/cjs/mixins/OxyServices.linkedAccounts.js +0 -79
- package/dist/cjs/mixins/OxyServices.location.js +0 -43
- package/dist/cjs/mixins/OxyServices.nodes.js +0 -175
- package/dist/cjs/mixins/OxyServices.notifications.js +0 -63
- package/dist/cjs/mixins/OxyServices.payment.js +0 -158
- package/dist/cjs/mixins/OxyServices.privacy.js +0 -199
- package/dist/cjs/mixins/OxyServices.reputation.js +0 -289
- package/dist/cjs/mixins/OxyServices.security.js +0 -89
- package/dist/cjs/mixins/OxyServices.store.js +0 -266
- package/dist/cjs/mixins/OxyServices.topics.js +0 -137
- package/dist/cjs/mixins/OxyServices.user.js +0 -954
- package/dist/cjs/mixins/OxyServices.utility.js +0 -1402
- package/dist/cjs/mixins/index.js +0 -136
- package/dist/cjs/mixins/mixinHelpers.js +0 -53
- package/dist/cjs/utils/webauthnOrigin.js +0 -51
- package/dist/esm/.tsbuildinfo +0 -1
- package/dist/esm/OxyServices.base.js +0 -388
- package/dist/esm/i18n/locales/locales/ar-SA.json +0 -306
- package/dist/esm/i18n/locales/locales/ca-ES.json +0 -306
- package/dist/esm/i18n/locales/locales/de-DE.json +0 -306
- package/dist/esm/i18n/locales/locales/en-US.json +0 -2127
- package/dist/esm/i18n/locales/locales/es-ES.json +0 -2127
- package/dist/esm/i18n/locales/locales/fr-FR.json +0 -306
- package/dist/esm/i18n/locales/locales/it-IT.json +0 -306
- package/dist/esm/i18n/locales/locales/ja-JP.json +0 -306
- package/dist/esm/i18n/locales/locales/ko-KR.json +0 -306
- package/dist/esm/i18n/locales/locales/pt-PT.json +0 -306
- package/dist/esm/i18n/locales/locales/zh-CN.json +0 -306
- package/dist/esm/mixins/OxyServices.accounts.js +0 -543
- package/dist/esm/mixins/OxyServices.agency.js +0 -151
- package/dist/esm/mixins/OxyServices.analytics.js +0 -46
- package/dist/esm/mixins/OxyServices.appData.js +0 -103
- package/dist/esm/mixins/OxyServices.assets.js +0 -851
- package/dist/esm/mixins/OxyServices.auth.js +0 -1455
- package/dist/esm/mixins/OxyServices.chains.js +0 -70
- package/dist/esm/mixins/OxyServices.civic.js +0 -605
- package/dist/esm/mixins/OxyServices.connectedApps.js +0 -92
- package/dist/esm/mixins/OxyServices.contacts.js +0 -47
- package/dist/esm/mixins/OxyServices.deviceBoot.js +0 -186
- package/dist/esm/mixins/OxyServices.devices.js +0 -113
- package/dist/esm/mixins/OxyServices.features.js +0 -332
- package/dist/esm/mixins/OxyServices.followGraph.js +0 -218
- package/dist/esm/mixins/OxyServices.identity.js +0 -558
- package/dist/esm/mixins/OxyServices.identityBackup.js +0 -169
- package/dist/esm/mixins/OxyServices.inference.js +0 -56
- package/dist/esm/mixins/OxyServices.language.js +0 -122
- package/dist/esm/mixins/OxyServices.linkedAccounts.js +0 -76
- package/dist/esm/mixins/OxyServices.location.js +0 -40
- package/dist/esm/mixins/OxyServices.nodes.js +0 -172
- package/dist/esm/mixins/OxyServices.notifications.js +0 -60
- package/dist/esm/mixins/OxyServices.payment.js +0 -155
- package/dist/esm/mixins/OxyServices.privacy.js +0 -196
- package/dist/esm/mixins/OxyServices.reputation.js +0 -286
- package/dist/esm/mixins/OxyServices.security.js +0 -86
- package/dist/esm/mixins/OxyServices.store.js +0 -263
- package/dist/esm/mixins/OxyServices.topics.js +0 -134
- package/dist/esm/mixins/OxyServices.user.js +0 -951
- package/dist/esm/mixins/OxyServices.utility.js +0 -1397
- package/dist/esm/mixins/index.js +0 -133
- package/dist/esm/mixins/mixinHelpers.js +0 -48
- package/dist/esm/utils/webauthnOrigin.js +0 -48
- package/dist/types/.tsbuildinfo +0 -1
- package/dist/types/OxyServices.base.d.ts +0 -189
- package/dist/types/mixins/OxyServices.accounts.d.ts +0 -868
- package/dist/types/mixins/OxyServices.agency.d.ts +0 -176
- package/dist/types/mixins/OxyServices.analytics.d.ts +0 -72
- package/dist/types/mixins/OxyServices.appData.d.ts +0 -108
- package/dist/types/mixins/OxyServices.assets.d.ts +0 -371
- package/dist/types/mixins/OxyServices.auth.d.ts +0 -998
- package/dist/types/mixins/OxyServices.chains.d.ts +0 -156
- package/dist/types/mixins/OxyServices.civic.d.ts +0 -520
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -184
- package/dist/types/mixins/OxyServices.contacts.d.ts +0 -100
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +0 -185
- package/dist/types/mixins/OxyServices.devices.d.ts +0 -103
- package/dist/types/mixins/OxyServices.features.d.ts +0 -250
- package/dist/types/mixins/OxyServices.followGraph.d.ts +0 -223
- package/dist/types/mixins/OxyServices.identity.d.ts +0 -337
- package/dist/types/mixins/OxyServices.identityBackup.d.ts +0 -129
- package/dist/types/mixins/OxyServices.inference.d.ts +0 -95
- package/dist/types/mixins/OxyServices.language.d.ts +0 -87
- package/dist/types/mixins/OxyServices.linkedAccounts.d.ts +0 -107
- package/dist/types/mixins/OxyServices.location.d.ts +0 -70
- package/dist/types/mixins/OxyServices.nodes.d.ts +0 -198
- package/dist/types/mixins/OxyServices.notifications.d.ts +0 -143
- package/dist/types/mixins/OxyServices.payment.d.ts +0 -117
- package/dist/types/mixins/OxyServices.privacy.d.ts +0 -146
- package/dist/types/mixins/OxyServices.reputation.d.ts +0 -202
- package/dist/types/mixins/OxyServices.security.d.ts +0 -84
- package/dist/types/mixins/OxyServices.store.d.ts +0 -334
- package/dist/types/mixins/OxyServices.topics.d.ts +0 -110
- package/dist/types/mixins/OxyServices.user.d.ts +0 -600
- package/dist/types/mixins/OxyServices.utility.d.ts +0 -526
- package/dist/types/mixins/index.d.ts +0 -87
- package/dist/types/mixins/mixinHelpers.d.ts +0 -31
- package/dist/types/utils/webauthnOrigin.d.ts +0 -32
- package/src/OxyServices.base.ts +0 -480
- package/src/__tests__/authSocket.test.ts +0 -96
- package/src/__tests__/fixEsmImports.test.ts +0 -132
- package/src/__tests__/httpServiceAbort.test.ts +0 -308
- package/src/__tests__/httpServiceActivityId.test.ts +0 -49
- package/src/__tests__/httpServiceAuthSelfAwait.test.ts +0 -108
- package/src/__tests__/httpServiceCache.test.ts +0 -318
- package/src/__tests__/httpServiceFormEncoded.test.ts +0 -139
- package/src/__tests__/httpServiceQueueDeadlock.test.ts +0 -128
- package/src/__tests__/httpServiceRateLimitedRefresh.test.ts +0 -160
- package/src/__tests__/httpServiceUnwrapEnvelope.test.ts +0 -115
- package/src/__tests__/httpServiceWrites.test.ts +0 -175
- package/src/__tests__/inSessionRefresh.test.ts +0 -313
- package/src/__tests__/linkedClient.test.ts +0 -363
- package/src/__tests__/nearExpiryMintStorm.test.ts +0 -165
- package/src/__tests__/parseHttpErrorBody.test.ts +0 -116
- package/src/__tests__/publicInterfaceParity.test.ts +0 -75
- package/src/__tests__/serverValueImportsDeclared.test.ts +0 -120
- package/src/__tests__/serviceIdentityWhenAnonymous.test.ts +0 -159
- package/src/__tests__/serviceTokenWorkloadFallback.test.ts +0 -85
- package/src/__tests__/userIdentity.test.ts +0 -143
- package/src/boot/__tests__/sessionColdBoot.identity.test.ts +0 -393
- package/src/boot/__tests__/sessionColdBoot.sharedDevice.test.ts +0 -325
- package/src/boot/__tests__/sessionColdBoot.test.ts +0 -570
- package/src/crypto/__tests__/backupMaterial.test.ts +0 -86
- package/src/crypto/__tests__/cryptoPrimitives.test.ts +0 -226
- package/src/crypto/__tests__/identityLink.test.ts +0 -18
- package/src/crypto/__tests__/identityMocks.ts +0 -125
- package/src/crypto/__tests__/identityProof.test.ts +0 -81
- package/src/crypto/__tests__/keyManager.atomicity.test.ts +0 -272
- package/src/crypto/__tests__/keyManager.cacheSafety.test.ts +0 -175
- package/src/crypto/__tests__/keyManager.deviceBackup.test.ts +0 -310
- package/src/crypto/__tests__/keyManager.identityStatus.test.ts +0 -217
- package/src/crypto/__tests__/keyManager.recoveryLadder.test.ts +0 -179
- package/src/crypto/__tests__/keyManager.recoveryMnemonic.test.ts +0 -138
- package/src/crypto/__tests__/keyManager.sharedSlotSync.test.ts +0 -150
- package/src/crypto/__tests__/keyManager.storageMigration.test.ts +0 -227
- package/src/crypto/__tests__/keyManager.test.ts +0 -329
- package/src/crypto/__tests__/polyfill.test.ts +0 -109
- package/src/crypto/__tests__/polyfillOrder.test.ts +0 -114
- package/src/crypto/__tests__/recoveryPhrase.test.ts +0 -61
- package/src/crypto/__tests__/registrationPow.test.ts +0 -61
- package/src/crypto/__tests__/scopedSeed.test.ts +0 -126
- package/src/crypto/__tests__/signChallengeShared.test.ts +0 -63
- package/src/crypto/__tests__/signedRecord.test.ts +0 -230
- package/src/i18n/__tests__/accountCategoryLabels.test.ts +0 -62
- package/src/i18n/__tests__/accountRoleLabels.test.ts +0 -54
- package/src/i18n/__tests__/reputationCategoryLabels.test.ts +0 -56
- package/src/i18n/__tests__/trustTierLabels.test.ts +0 -47
- package/src/i18n/locales/de-DE.json +0 -306
- package/src/i18n/locales/es-ES.json +0 -2127
- package/src/i18n/locales/ja-JP.json +0 -306
- package/src/inference/__tests__/OxyInferenceClient.test.ts +0 -899
- package/src/logger/__tests__/logger.test.ts +0 -207
- package/src/mixins/OxyServices.accounts.ts +0 -1330
- package/src/mixins/OxyServices.agency.ts +0 -353
- package/src/mixins/OxyServices.analytics.ts +0 -53
- package/src/mixins/OxyServices.appData.ts +0 -158
- package/src/mixins/OxyServices.assets.ts +0 -964
- package/src/mixins/OxyServices.auth.ts +0 -2083
- package/src/mixins/OxyServices.chains.ts +0 -134
- package/src/mixins/OxyServices.civic.ts +0 -945
- package/src/mixins/OxyServices.connectedApps.ts +0 -212
- package/src/mixins/OxyServices.contacts.ts +0 -73
- package/src/mixins/OxyServices.devices.ts +0 -120
- package/src/mixins/OxyServices.features.ts +0 -454
- package/src/mixins/OxyServices.followGraph.ts +0 -293
- package/src/mixins/OxyServices.identity.ts +0 -787
- package/src/mixins/OxyServices.identityBackup.ts +0 -250
- package/src/mixins/OxyServices.inference.ts +0 -57
- package/src/mixins/OxyServices.language.ts +0 -144
- package/src/mixins/OxyServices.linkedAccounts.ts +0 -129
- package/src/mixins/OxyServices.location.ts +0 -46
- package/src/mixins/OxyServices.nodes.ts +0 -337
- package/src/mixins/OxyServices.notifications.ts +0 -142
- package/src/mixins/OxyServices.payment.ts +0 -163
- package/src/mixins/OxyServices.privacy.ts +0 -219
- package/src/mixins/OxyServices.reputation.ts +0 -436
- package/src/mixins/OxyServices.security.ts +0 -110
- package/src/mixins/OxyServices.store.ts +0 -585
- package/src/mixins/OxyServices.topics.ts +0 -169
- package/src/mixins/OxyServices.user.ts +0 -1208
- package/src/mixins/OxyServices.utility.ts +0 -1803
- package/src/mixins/__tests__/OxyServices.civic.test.ts +0 -1095
- package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +0 -124
- package/src/mixins/__tests__/OxyServices.identity.test.ts +0 -301
- package/src/mixins/__tests__/OxyServices.nodes.test.ts +0 -341
- package/src/mixins/__tests__/OxyServices.rotateKey.test.ts +0 -323
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadata.test.ts +0 -192
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadataBySha.test.ts +0 -135
- package/src/mixins/__tests__/OxyServices.serviceLinkedDownloadUrl.test.ts +0 -139
- package/src/mixins/__tests__/accountEvents.test.ts +0 -158
- package/src/mixins/__tests__/accounts.test.ts +0 -727
- package/src/mixins/__tests__/agency.test.ts +0 -120
- package/src/mixins/__tests__/appData.test.ts +0 -203
- package/src/mixins/__tests__/assetCredentials.test.ts +0 -47
- package/src/mixins/__tests__/assetUpload.test.ts +0 -191
- package/src/mixins/__tests__/authRefusalObservability.test.ts +0 -396
- package/src/mixins/__tests__/backgroundCredential.httpIntegration.test.ts +0 -130
- package/src/mixins/__tests__/chains.test.ts +0 -113
- package/src/mixins/__tests__/commonsSignIn.test.ts +0 -1147
- package/src/mixins/__tests__/connectedApps.test.ts +0 -146
- package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +0 -113
- package/src/mixins/__tests__/discoveryErrorHandling.test.ts +0 -265
- package/src/mixins/__tests__/followCacheInvalidation.test.ts +0 -173
- package/src/mixins/__tests__/followGraph.test.ts +0 -147
- package/src/mixins/__tests__/followGraphPagination.test.ts +0 -271
- package/src/mixins/__tests__/getFileDownloadUrl.test.ts +0 -346
- package/src/mixins/__tests__/getFollowStatuses.test.ts +0 -95
- package/src/mixins/__tests__/getUsersByIds.test.ts +0 -176
- package/src/mixins/__tests__/identityBackup.test.ts +0 -315
- package/src/mixins/__tests__/identityLink.test.ts +0 -89
- package/src/mixins/__tests__/identityWriteCacheInvalidation.test.ts +0 -407
- package/src/mixins/__tests__/inferenceFactory.test.ts +0 -58
- package/src/mixins/__tests__/linkedAccounts.test.ts +0 -109
- package/src/mixins/__tests__/notifications.read.test.ts +0 -82
- package/src/mixins/__tests__/onTokensChanged.test.ts +0 -129
- package/src/mixins/__tests__/preSessionSkipAuth.test.ts +0 -284
- package/src/mixins/__tests__/privacyCacheInvalidation.test.ts +0 -155
- package/src/mixins/__tests__/reputation.test.ts +0 -522
- package/src/mixins/__tests__/serviceAuth.test.ts +0 -889
- package/src/mixins/__tests__/serviceTokenJwks.test.ts +0 -208
- package/src/mixins/__tests__/store.test.ts +0 -304
- package/src/mixins/__tests__/topics.test.ts +0 -155
- package/src/mixins/__tests__/userReadCacheBypass.test.ts +0 -129
- package/src/mixins/__tests__/userTokenAuth.test.ts +0 -746
- package/src/mixins/__tests__/verifyChallenge.test.ts +0 -161
- package/src/mixins/__tests__/verifyServiceActingAs.test.ts +0 -167
- package/src/mixins/__tests__/webauthnAuth.test.ts +0 -279
- package/src/mixins/index.ts +0 -203
- package/src/mixins/mixinHelpers.ts +0 -69
- package/src/server/__tests__/auth.test.ts +0 -78
- package/src/server/__tests__/capabilityTicket.test.ts +0 -111
- package/src/server/__tests__/cors.socket.test.ts +0 -225
- package/src/server/__tests__/cors.test.ts +0 -158
- package/src/server/__tests__/rateLimit.test.ts +0 -257
- package/src/server/__tests__/requesterAssertion.test.ts +0 -359
- package/src/server/__tests__/safeFetch.test.ts +0 -232
- package/src/server/__tests__/securityHeaders.test.ts +0 -387
- package/src/server/__tests__/serviceTokenAttribution.test.ts +0 -396
- package/src/server/__tests__/traffic.test.ts +0 -180
- package/src/server/__tests__/trafficNodeHttp.test.ts +0 -38
- package/src/server/__tests__/userInvalidation.test.ts +0 -203
- package/src/server/__tests__/verifySecret.test.ts +0 -40
- package/src/server/__tests__/workloadIdentity.client.test.ts +0 -16
- package/src/server/__tests__/workloadIdentity.test.ts +0 -128
- package/src/session/__tests__/SessionClient.additive.test.ts +0 -153
- package/src/session/__tests__/SessionClient.broadcastChannel.test.ts +0 -114
- package/src/session/__tests__/SessionClient.diagnostics.test.ts +0 -91
- package/src/session/__tests__/SessionClient.directory.test.ts +0 -688
- package/src/session/__tests__/SessionClient.httpIntegration.test.ts +0 -65
- package/src/session/__tests__/SessionClient.identityPin.test.ts +0 -175
- package/src/session/__tests__/SessionClient.rest.test.ts +0 -119
- package/src/session/__tests__/SessionClient.serverEvents.test.ts +0 -72
- package/src/session/__tests__/SessionClient.socket.test.ts +0 -202
- package/src/session/__tests__/SessionClient.socketFactory.test.ts +0 -81
- package/src/session/__tests__/SessionClient.state.test.ts +0 -78
- package/src/session/__tests__/SessionClient.switchTokenOrder.test.ts +0 -170
- package/src/session/__tests__/accountDelegationAccess.test.ts +0 -104
- package/src/session/__tests__/accountDialogController.test.ts +0 -2502
- package/src/session/__tests__/accountDialogShape.test.ts +0 -120
- package/src/session/__tests__/accountSwitchTargets.test.ts +0 -137
- package/src/session/__tests__/authStateStore.test.ts +0 -451
- package/src/session/__tests__/deviceDirectory.test.ts +0 -422
- package/src/session/__tests__/deviceSwitcherRows.test.ts +0 -223
- package/src/session/__tests__/identityPin.test.ts +0 -131
- package/src/session/__tests__/identitySession.test.ts +0 -194
- package/src/session/__tests__/projectSessionState.test.ts +0 -105
- package/src/session/__tests__/refresh.identityPin.test.ts +0 -307
- package/src/session/__tests__/refresh.test.ts +0 -606
- package/src/session/__tests__/sessionIntegration.test.ts +0 -209
- package/src/session/__tests__/sharedDeviceCredential.test.ts +0 -300
- package/src/utils/__tests__/accountUtils.test.ts +0 -151
- package/src/utils/__tests__/activityId.test.ts +0 -45
- package/src/utils/__tests__/asyncUtils.test.ts +0 -279
- package/src/utils/__tests__/authWebUrl.test.ts +0 -15
- package/src/utils/__tests__/cacheKey.test.ts +0 -0
- package/src/utils/__tests__/cacheLifecycle.test.ts +0 -65
- package/src/utils/__tests__/coldBoot.test.ts +0 -496
- package/src/utils/__tests__/commonsApproval.test.ts +0 -60
- package/src/utils/__tests__/identityCacheSweep.test.ts +0 -151
- package/src/utils/__tests__/languageUtils.test.ts +0 -244
- package/src/utils/__tests__/oauthPkce.test.ts +0 -303
- package/src/utils/__tests__/officialOrigins.test.ts +0 -31
- package/src/utils/__tests__/oxyServiceEnvironment.test.ts +0 -7
- package/src/utils/__tests__/profileLinks.test.ts +0 -180
- package/src/utils/__tests__/redactUrl.test.ts +0 -33
- package/src/utils/__tests__/registrableApex.test.ts +0 -62
- package/src/utils/__tests__/requestUtilsAbort.test.ts +0 -155
- package/src/utils/__tests__/textNormalization.test.ts +0 -205
- package/src/utils/__tests__/validationUtils.test.ts +0 -703
- package/src/utils/__tests__/webauthnOrigin.test.ts +0 -83
- package/src/utils/webauthnOrigin.ts +0 -52
|
@@ -1,606 +0,0 @@
|
|
|
1
|
-
import type { OxyServices } from '../../OxyServices';
|
|
2
|
-
import type { DeviceTokenMintResponse } from '@oxy.so/contracts';
|
|
3
|
-
import type { SessionLoginResponse } from '../../models/session';
|
|
4
|
-
import {
|
|
5
|
-
refreshPersistedSession,
|
|
6
|
-
startTokenRefreshScheduler,
|
|
7
|
-
type DeviceSecretMintOutcome,
|
|
8
|
-
} from '../refresh';
|
|
9
|
-
import {
|
|
10
|
-
createMemoryAuthStateStore,
|
|
11
|
-
type AuthStateStore,
|
|
12
|
-
type PersistedAuthState,
|
|
13
|
-
} from '../authStateStore';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* A real, per-client device-secret mint single-flight matching
|
|
17
|
-
* `HttpService.runSingleFlightDeviceSecretMint`: concurrent callers await the
|
|
18
|
-
* SAME in-flight mint and all receive its result; a fresh call after it settles
|
|
19
|
-
* starts a new one.
|
|
20
|
-
*/
|
|
21
|
-
function makeMintSingleFlight(): (mint: () => Promise<DeviceSecretMintOutcome>) => Promise<DeviceSecretMintOutcome> {
|
|
22
|
-
let inFlight: Promise<DeviceSecretMintOutcome> | null = null;
|
|
23
|
-
return (mint) => {
|
|
24
|
-
if (!inFlight) {
|
|
25
|
-
inFlight = mint().finally(() => {
|
|
26
|
-
inFlight = null;
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
return inFlight;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** The persisted zero-cookie mint credential the refresh reads. */
|
|
34
|
-
const STORED: PersistedAuthState = {
|
|
35
|
-
sessionId: 'sess-old',
|
|
36
|
-
userId: 'user-1',
|
|
37
|
-
deviceId: 'dev-mint',
|
|
38
|
-
deviceSecret: 'ds-secret-orig',
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/** A successful `POST /session/device/token` mint (rotates the secret + active account). */
|
|
42
|
-
const MINT: DeviceTokenMintResponse = {
|
|
43
|
-
accessToken: 'access-new',
|
|
44
|
-
expiresAt: '2030-01-01T00:00:00.000Z',
|
|
45
|
-
nextDeviceSecret: 'ds-next-secret',
|
|
46
|
-
state: {
|
|
47
|
-
deviceId: 'dev-mint',
|
|
48
|
-
accounts: [{ accountId: 'user-1', sessionId: 'sess-new', authuser: 0 }],
|
|
49
|
-
activeAccountId: 'user-1',
|
|
50
|
-
revision: 4,
|
|
51
|
-
updatedAt: 1_700_000_000_000,
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
interface RefreshMockOverrides {
|
|
56
|
-
mintFromDeviceSecret?: OxyServices['mintFromDeviceSecret'];
|
|
57
|
-
signInWithSharedIdentity?: OxyServices['signInWithSharedIdentity'];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function makeOxy(
|
|
61
|
-
overrides: RefreshMockOverrides = {},
|
|
62
|
-
): {
|
|
63
|
-
oxy: OxyServices;
|
|
64
|
-
setTokens: jest.Mock;
|
|
65
|
-
noteRefreshRateLimited: jest.Mock;
|
|
66
|
-
/** `HttpService`'s session epoch; bump it to simulate a sign-out mid-refresh. */
|
|
67
|
-
epoch: { current: number };
|
|
68
|
-
/** `HttpService.hasSessionEnded()`: a sign-out with no token planted since. */
|
|
69
|
-
ended: { current: boolean };
|
|
70
|
-
} {
|
|
71
|
-
const setTokens = jest.fn();
|
|
72
|
-
const epoch = { current: 0 };
|
|
73
|
-
const ended = { current: false };
|
|
74
|
-
const noteRefreshRateLimited = jest.fn();
|
|
75
|
-
const oxy = {
|
|
76
|
-
setTokens,
|
|
77
|
-
mintFromDeviceSecret: overrides.mintFromDeviceSecret ?? (async () => MINT),
|
|
78
|
-
signInWithSharedIdentity: overrides.signInWithSharedIdentity ?? (async () => null),
|
|
79
|
-
// The rotating mint runs under the client's process-wide single-flight; the
|
|
80
|
-
// arm reaches for it via `oxy.httpService.runSingleFlightDeviceSecretMint`.
|
|
81
|
-
httpService: {
|
|
82
|
-
runSingleFlightDeviceSecretMint: makeMintSingleFlight(),
|
|
83
|
-
noteRefreshRateLimited,
|
|
84
|
-
getSessionEpoch: () => epoch.current,
|
|
85
|
-
hasSessionEnded: () => ended.current,
|
|
86
|
-
},
|
|
87
|
-
} as unknown as OxyServices;
|
|
88
|
-
return { oxy, setTokens, noteRefreshRateLimited, epoch, ended };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
describe('refreshPersistedSession — arm 1 (device-secret mint)', () => {
|
|
92
|
-
it('mints, plants, persists the rotated secret + active account, and returns the token', async () => {
|
|
93
|
-
const store = createMemoryAuthStateStore();
|
|
94
|
-
await store.save(STORED);
|
|
95
|
-
const { oxy, setTokens } = makeOxy();
|
|
96
|
-
|
|
97
|
-
const token = await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
98
|
-
|
|
99
|
-
expect(token).toBe('access-new');
|
|
100
|
-
expect(setTokens).toHaveBeenCalledWith('access-new');
|
|
101
|
-
expect(await store.load()).toEqual({
|
|
102
|
-
sessionId: 'sess-new',
|
|
103
|
-
userId: 'user-1',
|
|
104
|
-
deviceId: 'dev-mint',
|
|
105
|
-
deviceSecret: 'ds-next-secret',
|
|
106
|
-
accessToken: 'access-new',
|
|
107
|
-
expiresAt: '2030-01-01T00:00:00.000Z',
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('presents the persisted deviceId + deviceSecret to the mint', async () => {
|
|
112
|
-
const store = createMemoryAuthStateStore();
|
|
113
|
-
await store.save(STORED);
|
|
114
|
-
const mintFromDeviceSecret = jest.fn(async () => MINT);
|
|
115
|
-
const { oxy } = makeOxy({ mintFromDeviceSecret });
|
|
116
|
-
|
|
117
|
-
await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
118
|
-
|
|
119
|
-
expect(mintFromDeviceSecret).toHaveBeenCalledWith('dev-mint', 'ds-secret-orig');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('drops only the secret (keeps deviceId) on a 401 and falls to shared-key when native', async () => {
|
|
123
|
-
const store = createMemoryAuthStateStore();
|
|
124
|
-
await store.save(STORED);
|
|
125
|
-
const SHARED: SessionLoginResponse = {
|
|
126
|
-
sessionId: 'sess-shared',
|
|
127
|
-
deviceId: 'dev-1',
|
|
128
|
-
expiresAt: '2030-01-01T00:00:00.000Z',
|
|
129
|
-
user: { id: 'user-1', username: 'u', name: {}, avatar: undefined },
|
|
130
|
-
accessToken: 'access-shared',
|
|
131
|
-
};
|
|
132
|
-
const signInWithSharedIdentity = jest.fn(async () => SHARED);
|
|
133
|
-
const { oxy } = makeOxy({
|
|
134
|
-
mintFromDeviceSecret: async () => {
|
|
135
|
-
throw Object.assign(new Error('invalid_device_secret'), { status: 401 });
|
|
136
|
-
},
|
|
137
|
-
signInWithSharedIdentity,
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
const token = await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true });
|
|
141
|
-
|
|
142
|
-
expect(token).toBe('access-shared');
|
|
143
|
-
expect(signInWithSharedIdentity).toHaveBeenCalledTimes(1);
|
|
144
|
-
const persisted = await store.load();
|
|
145
|
-
expect(persisted?.deviceSecret).toBeUndefined();
|
|
146
|
-
expect(persisted?.deviceId).toBe('dev-mint');
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('clears the store on a 401 when there is no shared-key fallback (web)', async () => {
|
|
150
|
-
const store = createMemoryAuthStateStore();
|
|
151
|
-
await store.save(STORED);
|
|
152
|
-
const { oxy } = makeOxy({
|
|
153
|
-
mintFromDeviceSecret: async () => {
|
|
154
|
-
throw Object.assign(new Error('no_active_session'), { status: 401 });
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const token = await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
159
|
-
|
|
160
|
-
expect(token).toBeNull();
|
|
161
|
-
expect(await store.load()).toBeNull();
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('KEEPS the store and returns null on a transient (500 / network) error', async () => {
|
|
165
|
-
const store = createMemoryAuthStateStore();
|
|
166
|
-
await store.save(STORED);
|
|
167
|
-
const signInWithSharedIdentity = jest.fn(async () => null);
|
|
168
|
-
const { oxy } = makeOxy({
|
|
169
|
-
mintFromDeviceSecret: async () => {
|
|
170
|
-
throw Object.assign(new Error('server'), { status: 500 });
|
|
171
|
-
},
|
|
172
|
-
signInWithSharedIdentity,
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// A transient failure must NOT drop the credential nor fall through to shared-key.
|
|
176
|
-
expect(await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true })).toBeNull();
|
|
177
|
-
expect(await store.load()).toEqual(STORED);
|
|
178
|
-
expect(signInWithSharedIdentity).not.toHaveBeenCalled();
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('KEEPS the store on an UNRECOGNIZED 401 (proxy / middleware / deploy-window) — never wipes the credential on an ambiguous 401', async () => {
|
|
182
|
-
const store = createMemoryAuthStateStore();
|
|
183
|
-
await store.save(STORED);
|
|
184
|
-
const signInWithSharedIdentity = jest.fn(async () => null);
|
|
185
|
-
const { oxy } = makeOxy({
|
|
186
|
-
mintFromDeviceSecret: async () => {
|
|
187
|
-
// A 401 whose body is NEITHER `invalid_device_secret` NOR `no_active_session`
|
|
188
|
-
// — an auth-layer / proxy / starting-instance 401 common during a deploy
|
|
189
|
-
// window. It is NOT proof the secret diverged, so the durable device
|
|
190
|
-
// credential must survive (treated as transient) and a later attempt self-heals.
|
|
191
|
-
throw Object.assign(new Error('Unauthorized'), { status: 401 });
|
|
192
|
-
},
|
|
193
|
-
signInWithSharedIdentity,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
expect(await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true })).toBeNull();
|
|
197
|
-
expect(await store.load()).toEqual(STORED);
|
|
198
|
-
expect(signInWithSharedIdentity).not.toHaveBeenCalled();
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('KEEPS the store on a 429 and does NOT fall through to shared-key — a rationed mint never judged the secret', async () => {
|
|
202
|
-
const store = createMemoryAuthStateStore();
|
|
203
|
-
await store.save(STORED);
|
|
204
|
-
const signInWithSharedIdentity = jest.fn(async () => null);
|
|
205
|
-
const { oxy } = makeOxy({
|
|
206
|
-
mintFromDeviceSecret: async () => {
|
|
207
|
-
throw Object.assign(new Error('Too many requests'), { status: 429 });
|
|
208
|
-
},
|
|
209
|
-
signInWithSharedIdentity,
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
expect(await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true })).toBeNull();
|
|
213
|
-
expect(await store.load()).toEqual(STORED);
|
|
214
|
-
expect(signInWithSharedIdentity).not.toHaveBeenCalled();
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it('tells HttpService to lengthen the refresh cooldown when the mint is rate limited', async () => {
|
|
218
|
-
const store = createMemoryAuthStateStore();
|
|
219
|
-
await store.save(STORED);
|
|
220
|
-
const { oxy, noteRefreshRateLimited } = makeOxy({
|
|
221
|
-
mintFromDeviceSecret: async () => {
|
|
222
|
-
throw Object.assign(new Error('Too many requests'), { status: 429 });
|
|
223
|
-
},
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
227
|
-
|
|
228
|
-
expect(noteRefreshRateLimited).toHaveBeenCalledTimes(1);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('does NOT lengthen the cooldown for failures the server did not ration', async () => {
|
|
232
|
-
const store = createMemoryAuthStateStore();
|
|
233
|
-
await store.save(STORED);
|
|
234
|
-
const { oxy, noteRefreshRateLimited } = makeOxy({
|
|
235
|
-
mintFromDeviceSecret: async () => {
|
|
236
|
-
throw Object.assign(new Error('server'), { status: 500 });
|
|
237
|
-
},
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
241
|
-
|
|
242
|
-
expect(noteRefreshRateLimited).not.toHaveBeenCalled();
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
describe('refreshPersistedSession — arm 2 (native shared-key fallback)', () => {
|
|
247
|
-
const SHARED_SESSION: SessionLoginResponse = {
|
|
248
|
-
sessionId: 'sess-shared',
|
|
249
|
-
deviceId: 'dev-1',
|
|
250
|
-
expiresAt: '2030-01-01T00:00:00.000Z',
|
|
251
|
-
user: { id: 'user-1', username: 'u', name: {}, avatar: undefined },
|
|
252
|
-
accessToken: 'access-shared',
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
it('re-mints via shared identity when there is no persisted secret', async () => {
|
|
256
|
-
const store = createMemoryAuthStateStore(); // no stored device secret
|
|
257
|
-
const signInWithSharedIdentity = jest.fn(async () => SHARED_SESSION);
|
|
258
|
-
const { oxy } = makeOxy({ signInWithSharedIdentity });
|
|
259
|
-
|
|
260
|
-
const token = await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true });
|
|
261
|
-
|
|
262
|
-
expect(token).toBe('access-shared');
|
|
263
|
-
expect(signInWithSharedIdentity).toHaveBeenCalledTimes(1);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
it('does NOT try shared-key when the fallback is disabled (web)', async () => {
|
|
267
|
-
const store = createMemoryAuthStateStore();
|
|
268
|
-
const signInWithSharedIdentity = jest.fn(async () => SHARED_SESSION);
|
|
269
|
-
const { oxy } = makeOxy({ signInWithSharedIdentity });
|
|
270
|
-
|
|
271
|
-
expect(await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false })).toBeNull();
|
|
272
|
-
expect(signInWithSharedIdentity).not.toHaveBeenCalled();
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it('returns null when the shared-key re-mint yields no session', async () => {
|
|
276
|
-
const store = createMemoryAuthStateStore();
|
|
277
|
-
const signInWithSharedIdentity = jest.fn(async () => null);
|
|
278
|
-
const { oxy } = makeOxy({ signInWithSharedIdentity });
|
|
279
|
-
|
|
280
|
-
expect(await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true })).toBeNull();
|
|
281
|
-
expect(signInWithSharedIdentity).toHaveBeenCalledTimes(1);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it('persists the recovered credential from the shared-key re-mint (repopulates the fast lane)', async () => {
|
|
285
|
-
// Bug #3: an in-session shared-key recovery must repopulate the durable
|
|
286
|
-
// device credential, not leave the fast device-secret lane empty.
|
|
287
|
-
const store = createMemoryAuthStateStore(); // no persisted secret → arm 1 skips
|
|
288
|
-
const RECOVERED: SessionLoginResponse = {
|
|
289
|
-
sessionId: 'sess-shared',
|
|
290
|
-
deviceId: 'dev-shared',
|
|
291
|
-
deviceSecret: 'ds-shared-secret',
|
|
292
|
-
expiresAt: '2030-01-01T00:00:00.000Z',
|
|
293
|
-
user: { id: 'user-shared', username: 'u', name: {}, avatar: undefined },
|
|
294
|
-
accessToken: 'access-shared',
|
|
295
|
-
};
|
|
296
|
-
const { oxy } = makeOxy({ signInWithSharedIdentity: jest.fn(async () => RECOVERED) });
|
|
297
|
-
|
|
298
|
-
const token = await refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true });
|
|
299
|
-
|
|
300
|
-
expect(token).toBe('access-shared');
|
|
301
|
-
expect(await store.load()).toEqual({
|
|
302
|
-
sessionId: 'sess-shared',
|
|
303
|
-
userId: 'user-shared',
|
|
304
|
-
deviceId: 'dev-shared',
|
|
305
|
-
deviceSecret: 'ds-shared-secret',
|
|
306
|
-
accessToken: 'access-shared',
|
|
307
|
-
expiresAt: '2030-01-01T00:00:00.000Z',
|
|
308
|
-
});
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
describe('refreshPersistedSession — a sign-out mid-refresh', () => {
|
|
313
|
-
it('arm 1: plants nothing and leaves a cleared store cleared', async () => {
|
|
314
|
-
const store = createMemoryAuthStateStore();
|
|
315
|
-
await store.save(STORED);
|
|
316
|
-
let respond!: () => void;
|
|
317
|
-
const { oxy, setTokens, epoch } = makeOxy({
|
|
318
|
-
mintFromDeviceSecret: () =>
|
|
319
|
-
new Promise((resolve) => {
|
|
320
|
-
respond = () => resolve(MINT);
|
|
321
|
-
}),
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
const pending = refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true });
|
|
325
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
326
|
-
// The sign-out: the credential is dropped and the session epoch moves.
|
|
327
|
-
await store.clear();
|
|
328
|
-
epoch.current += 1;
|
|
329
|
-
respond();
|
|
330
|
-
|
|
331
|
-
await expect(pending).resolves.toBeNull();
|
|
332
|
-
expect(setTokens).not.toHaveBeenCalled();
|
|
333
|
-
expect(await store.load()).toBeNull();
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it('arm 1: still persists the rotated secret when the store kept the credential', async () => {
|
|
337
|
-
const store = createMemoryAuthStateStore();
|
|
338
|
-
await store.save(STORED);
|
|
339
|
-
let respond!: () => void;
|
|
340
|
-
const { oxy, setTokens, epoch } = makeOxy({
|
|
341
|
-
mintFromDeviceSecret: () =>
|
|
342
|
-
new Promise((resolve) => {
|
|
343
|
-
respond = () => resolve(MINT);
|
|
344
|
-
}),
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
const pending = refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
348
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
349
|
-
// A local teardown that keeps the store (so a reload can restore): the
|
|
350
|
-
// server rotated the secret, and the store must not be left holding the old one.
|
|
351
|
-
epoch.current += 1;
|
|
352
|
-
respond();
|
|
353
|
-
|
|
354
|
-
await expect(pending).resolves.toBeNull();
|
|
355
|
-
expect(setTokens).not.toHaveBeenCalled();
|
|
356
|
-
expect((await store.load())?.deviceSecret).toBe('ds-next-secret');
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
it('arm 2: the shared keychain does not sign the user back in', async () => {
|
|
360
|
-
const store = createMemoryAuthStateStore();
|
|
361
|
-
let respond!: () => void;
|
|
362
|
-
const signInWithSharedIdentity = jest.fn(
|
|
363
|
-
(_opts?: { plantTokens?: boolean }) =>
|
|
364
|
-
new Promise<SessionLoginResponse>((resolve) => {
|
|
365
|
-
respond = () =>
|
|
366
|
-
resolve({
|
|
367
|
-
sessionId: 'sess-shared',
|
|
368
|
-
deviceId: 'dev-1',
|
|
369
|
-
deviceSecret: 'ds-shared',
|
|
370
|
-
expiresAt: '2030-01-01T00:00:00.000Z',
|
|
371
|
-
user: { id: 'user-1', username: 'u', name: {}, avatar: undefined },
|
|
372
|
-
accessToken: 'access-shared',
|
|
373
|
-
});
|
|
374
|
-
}),
|
|
375
|
-
);
|
|
376
|
-
const { oxy, setTokens, epoch } = makeOxy({ signInWithSharedIdentity });
|
|
377
|
-
|
|
378
|
-
const pending = refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true });
|
|
379
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
380
|
-
epoch.current += 1;
|
|
381
|
-
respond();
|
|
382
|
-
|
|
383
|
-
await expect(pending).resolves.toBeNull();
|
|
384
|
-
expect(signInWithSharedIdentity).toHaveBeenCalledWith({ plantTokens: false });
|
|
385
|
-
expect(setTokens).not.toHaveBeenCalled();
|
|
386
|
-
expect(await store.load()).toBeNull();
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
describe('refreshPersistedSession — after a sign-out', () => {
|
|
391
|
-
it('does not re-sign-in with the shared keychain', async () => {
|
|
392
|
-
const store = createMemoryAuthStateStore();
|
|
393
|
-
const signInWithSharedIdentity = jest.fn(async () => null);
|
|
394
|
-
const { oxy, setTokens, ended } = makeOxy({ signInWithSharedIdentity });
|
|
395
|
-
ended.current = true;
|
|
396
|
-
|
|
397
|
-
await expect(refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true })).resolves.toBeNull();
|
|
398
|
-
expect(signInWithSharedIdentity).not.toHaveBeenCalled();
|
|
399
|
-
expect(setTokens).not.toHaveBeenCalled();
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
it('still mints from a device credential the store holds (a sign-in made in another tab)', async () => {
|
|
403
|
-
const store = createMemoryAuthStateStore();
|
|
404
|
-
await store.save(STORED);
|
|
405
|
-
const { oxy, setTokens, ended } = makeOxy();
|
|
406
|
-
ended.current = true;
|
|
407
|
-
|
|
408
|
-
await expect(refreshPersistedSession({ oxy, store, allowSharedKeyFallback: true })).resolves.toBe('access-new');
|
|
409
|
-
expect(setTokens).toHaveBeenCalledWith('access-new');
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
describe('refreshPersistedSession — single-flight (no double-rotation)', () => {
|
|
414
|
-
it('coalesces two concurrent mints into ONE server rotation; the store holds the final current secret', async () => {
|
|
415
|
-
// The server rotates the secret on every mint. Two concurrent lanes must
|
|
416
|
-
// therefore share ONE in-flight mint (one rotation) or the store could
|
|
417
|
-
// converge on a superseded secret.
|
|
418
|
-
const store = createMemoryAuthStateStore();
|
|
419
|
-
await store.save(STORED);
|
|
420
|
-
|
|
421
|
-
let release: (() => void) | null = null;
|
|
422
|
-
const gate = new Promise<void>((resolve) => {
|
|
423
|
-
release = resolve;
|
|
424
|
-
});
|
|
425
|
-
const mintFromDeviceSecret = jest.fn(async (deviceId: string, deviceSecret: string) => {
|
|
426
|
-
// Block until BOTH callers have entered so the single-flight is exercised.
|
|
427
|
-
await gate;
|
|
428
|
-
expect(deviceId).toBe('dev-mint');
|
|
429
|
-
expect(deviceSecret).toBe('ds-secret-orig');
|
|
430
|
-
return MINT;
|
|
431
|
-
});
|
|
432
|
-
const { oxy, setTokens } = makeOxy({ mintFromDeviceSecret });
|
|
433
|
-
|
|
434
|
-
const first = refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
435
|
-
const second = refreshPersistedSession({ oxy, store, allowSharedKeyFallback: false });
|
|
436
|
-
// Both callers entered while the mint is in flight.
|
|
437
|
-
release?.();
|
|
438
|
-
const [t1, t2] = await Promise.all([first, second]);
|
|
439
|
-
|
|
440
|
-
// Exactly one server rotation despite two concurrent callers…
|
|
441
|
-
expect(mintFromDeviceSecret).toHaveBeenCalledTimes(1);
|
|
442
|
-
// …both callers received the same minted token…
|
|
443
|
-
expect(t1).toBe('access-new');
|
|
444
|
-
expect(t2).toBe('access-new');
|
|
445
|
-
// …and the durable store converged on the rotated (current) secret.
|
|
446
|
-
expect((await store.load())?.deviceSecret).toBe('ds-next-secret');
|
|
447
|
-
// The token was planted exactly once (inside the single-flighted mint).
|
|
448
|
-
expect(setTokens).toHaveBeenCalledTimes(1);
|
|
449
|
-
});
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
describe('refreshPersistedSession — durable persist failure is fatal to the mint', () => {
|
|
453
|
-
it('does NOT plant a token when the rotated secret cannot be durably persisted', async () => {
|
|
454
|
-
// Bug #2: a mint that rotated the server secret but could not persist it must
|
|
455
|
-
// not leave the process advertising a session on an unsaved, soon-dead secret.
|
|
456
|
-
const failingStore: AuthStateStore = {
|
|
457
|
-
load: async () => STORED,
|
|
458
|
-
save: async () => false, // durable write did not land
|
|
459
|
-
clear: async () => undefined,
|
|
460
|
-
};
|
|
461
|
-
const mintFromDeviceSecret = jest.fn(async () => MINT);
|
|
462
|
-
const { oxy, setTokens } = makeOxy({ mintFromDeviceSecret });
|
|
463
|
-
|
|
464
|
-
const token = await refreshPersistedSession({
|
|
465
|
-
oxy,
|
|
466
|
-
store: failingStore,
|
|
467
|
-
allowSharedKeyFallback: false,
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
// The mint ran (the server rotated) but the token was NOT planted…
|
|
471
|
-
expect(mintFromDeviceSecret).toHaveBeenCalledTimes(1);
|
|
472
|
-
expect(setTokens).not.toHaveBeenCalled();
|
|
473
|
-
// …and the lane reports failure rather than a healthy session.
|
|
474
|
-
expect(token).toBeNull();
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
it('does NOT fall through to the shared-key arm on a persist failure', async () => {
|
|
478
|
-
const failingStore: AuthStateStore = {
|
|
479
|
-
load: async () => STORED,
|
|
480
|
-
save: async () => false,
|
|
481
|
-
clear: async () => undefined,
|
|
482
|
-
};
|
|
483
|
-
const signInWithSharedIdentity = jest.fn(async () => null);
|
|
484
|
-
const { oxy } = makeOxy({
|
|
485
|
-
mintFromDeviceSecret: async () => MINT,
|
|
486
|
-
signInWithSharedIdentity,
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
await refreshPersistedSession({ oxy, store: failingStore, allowSharedKeyFallback: true });
|
|
490
|
-
|
|
491
|
-
// A storage failure is not a bad-secret signal — the shared-key arm must not run.
|
|
492
|
-
expect(signInWithSharedIdentity).not.toHaveBeenCalled();
|
|
493
|
-
});
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
describe('startTokenRefreshScheduler', () => {
|
|
497
|
-
function makeSchedulerOxy(expiresInSeconds: number | null): {
|
|
498
|
-
oxy: OxyServices;
|
|
499
|
-
refreshAccessToken: jest.Mock;
|
|
500
|
-
} {
|
|
501
|
-
let cleared = false;
|
|
502
|
-
const refreshAccessToken = jest.fn(async () => {
|
|
503
|
-
cleared = true; // stop the reschedule loop after the first fire
|
|
504
|
-
return null;
|
|
505
|
-
});
|
|
506
|
-
const nowSec = Math.floor(Date.now() / 1000);
|
|
507
|
-
const oxy = {
|
|
508
|
-
getAccessToken: () => (cleared ? null : 'tok'),
|
|
509
|
-
getAccessTokenExpiry: () => (expiresInSeconds === null ? null : nowSec + expiresInSeconds),
|
|
510
|
-
onTokensChanged: () => () => undefined,
|
|
511
|
-
httpService: { refreshAccessToken },
|
|
512
|
-
} as unknown as OxyServices;
|
|
513
|
-
return { oxy, refreshAccessToken };
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
afterEach(() => {
|
|
517
|
-
jest.useRealTimers();
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
it('fires a refresh ~60s before expiry', async () => {
|
|
521
|
-
jest.useFakeTimers();
|
|
522
|
-
const { oxy, refreshAccessToken } = makeSchedulerOxy(120);
|
|
523
|
-
const handle = startTokenRefreshScheduler(oxy);
|
|
524
|
-
|
|
525
|
-
expect(refreshAccessToken).not.toHaveBeenCalled();
|
|
526
|
-
await jest.advanceTimersByTimeAsync(60_000);
|
|
527
|
-
expect(refreshAccessToken).toHaveBeenCalledWith('preflight');
|
|
528
|
-
|
|
529
|
-
handle.dispose();
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
it('no-ops cleanly for an opaque token with no exp', () => {
|
|
533
|
-
jest.useFakeTimers();
|
|
534
|
-
const { oxy, refreshAccessToken } = makeSchedulerOxy(null);
|
|
535
|
-
const handle = startTokenRefreshScheduler(oxy);
|
|
536
|
-
jest.advanceTimersByTime(10 * 60_000);
|
|
537
|
-
expect(refreshAccessToken).not.toHaveBeenCalled();
|
|
538
|
-
handle.dispose();
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
it('backs off on repeated failure — bounded attempts, never a zero-delay busy loop', async () => {
|
|
542
|
-
jest.useFakeTimers();
|
|
543
|
-
// Already-expired token + a refresh that ALWAYS fails. The old code floored
|
|
544
|
-
// the delay to 0 and re-armed in the finally block → a tight loop that would
|
|
545
|
-
// exhaust jest's 100k-timer guard. The backoff schedule fires only a handful
|
|
546
|
-
// of times per simulated minute.
|
|
547
|
-
const refreshAccessToken = jest.fn(async () => null);
|
|
548
|
-
const nowSec = Math.floor(Date.now() / 1000);
|
|
549
|
-
const oxy = {
|
|
550
|
-
getAccessToken: () => 'tok',
|
|
551
|
-
getAccessTokenExpiry: () => nowSec - 10,
|
|
552
|
-
onTokensChanged: () => () => undefined,
|
|
553
|
-
httpService: { refreshAccessToken },
|
|
554
|
-
} as unknown as OxyServices;
|
|
555
|
-
|
|
556
|
-
const handle = startTokenRefreshScheduler(oxy);
|
|
557
|
-
await jest.advanceTimersByTimeAsync(60_000);
|
|
558
|
-
|
|
559
|
-
expect(refreshAccessToken.mock.calls.length).toBeGreaterThan(0);
|
|
560
|
-
expect(refreshAccessToken.mock.calls.length).toBeLessThan(10);
|
|
561
|
-
handle.dispose();
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
it('resets the backoff after a successful refresh', async () => {
|
|
565
|
-
jest.useFakeTimers();
|
|
566
|
-
// Expiry is always ~1h from NOW, so a successful refresh genuinely pushes
|
|
567
|
-
// the token out (as a real rotation would). Fail once, then succeed.
|
|
568
|
-
const refreshAccessToken = jest
|
|
569
|
-
.fn<Promise<string | null>, [unknown]>()
|
|
570
|
-
.mockResolvedValueOnce(null)
|
|
571
|
-
.mockResolvedValue('fresh');
|
|
572
|
-
const oxy = {
|
|
573
|
-
getAccessToken: () => 'tok',
|
|
574
|
-
getAccessTokenExpiry: () => Math.floor(Date.now() / 1000) + 3600,
|
|
575
|
-
onTokensChanged: () => () => undefined,
|
|
576
|
-
httpService: { refreshAccessToken },
|
|
577
|
-
} as unknown as OxyServices;
|
|
578
|
-
|
|
579
|
-
const handle = startTokenRefreshScheduler(oxy);
|
|
580
|
-
// First fire ~ (3600-60)s out (fails → 5s backoff), then the backoff fire
|
|
581
|
-
// succeeds and re-arms ~1h out from the (now-fresh) expiry.
|
|
582
|
-
await jest.advanceTimersByTimeAsync((3600 - 60) * 1000);
|
|
583
|
-
await jest.advanceTimersByTimeAsync(5_000);
|
|
584
|
-
const callsAfterSuccess = refreshAccessToken.mock.calls.length;
|
|
585
|
-
expect(callsAfterSuccess).toBe(2); // one failure + one success
|
|
586
|
-
// A further minute must NOT produce a burst — the healthy re-arm is ~1h out.
|
|
587
|
-
await jest.advanceTimersByTimeAsync(60_000);
|
|
588
|
-
expect(refreshAccessToken.mock.calls.length).toBe(callsAfterSuccess);
|
|
589
|
-
handle.dispose();
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
it('calls unref() on its timer so it never holds the event loop', () => {
|
|
593
|
-
const unref = jest.fn();
|
|
594
|
-
const setTimeoutSpy = jest
|
|
595
|
-
.spyOn(global, 'setTimeout')
|
|
596
|
-
.mockReturnValue({ unref } as unknown as ReturnType<typeof setTimeout>);
|
|
597
|
-
const { oxy } = makeSchedulerOxy(120);
|
|
598
|
-
|
|
599
|
-
const handle = startTokenRefreshScheduler(oxy);
|
|
600
|
-
expect(setTimeoutSpy).toHaveBeenCalled();
|
|
601
|
-
expect(unref).toHaveBeenCalled();
|
|
602
|
-
|
|
603
|
-
handle.dispose();
|
|
604
|
-
setTimeoutSpy.mockRestore();
|
|
605
|
-
});
|
|
606
|
-
});
|