@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,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `scripts/fix-esm-imports.mjs` must rewrite DYNAMIC relative imports too.
|
|
3
|
-
*
|
|
4
|
-
* ## The failure this exists for, which happened
|
|
5
|
-
*
|
|
6
|
-
* This package writes relative specifiers without an extension — legal under
|
|
7
|
-
* `moduleResolution: bundler`, illegal in Node's ESM resolver — and the
|
|
8
|
-
* post-build script adds the extension back. For its first life the script's
|
|
9
|
-
* pattern was `(?:from|import)\s+['"]`, which cannot match `import('./x')`:
|
|
10
|
-
* the keyword is followed by a parenthesis, not whitespace. Every dynamic
|
|
11
|
-
* import therefore shipped extensionless in `dist/esm`.
|
|
12
|
-
*
|
|
13
|
-
* `OxyServices.getServiceToken()` loads `../server/workloadIdentity` that way
|
|
14
|
-
* to decide whether this process can attest its workload identity (ADR 0026),
|
|
15
|
-
* and it does so inside a `try/catch` that reads any failure as "cannot attest
|
|
16
|
-
* here". So in every ESM consumer of the BUILT package the ADR 0026 fallback
|
|
17
|
-
* was dead, and a service whose task role attests perfectly well was told
|
|
18
|
-
* `Service credentials not provided` — which is what a deployment sees the
|
|
19
|
-
* moment its key pair is removed, and the reason `mention-mcp` and `alia` could
|
|
20
|
-
* not complete the migration while `mention`, `allo` and `alia-integrations`
|
|
21
|
-
* (all CommonJS, where `require()` supplies the extension) already had.
|
|
22
|
-
*
|
|
23
|
-
* ## Why this spawns the real script
|
|
24
|
-
*
|
|
25
|
-
* The defect is in the build OUTPUT, and core's CI job runs jest without
|
|
26
|
-
* building the package, so a test that reads `dist/esm` would pass by finding
|
|
27
|
-
* nothing. `serviceTokenWorkloadFallback.test.ts` cannot catch it either: jest
|
|
28
|
-
* resolves extensionless specifiers, and it mocks that module by name. The one
|
|
29
|
-
* thing that measures the real behaviour without a build is to run the script
|
|
30
|
-
* over a fixture and read what it wrote.
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
import { spawnSync } from 'node:child_process';
|
|
34
|
-
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
35
|
-
import { tmpdir } from 'node:os';
|
|
36
|
-
import path from 'node:path';
|
|
37
|
-
|
|
38
|
-
const script = path.resolve(__dirname, '../../scripts/fix-esm-imports.mjs');
|
|
39
|
-
|
|
40
|
-
function runOnFixture(files: Record<string, string>): Record<string, string> {
|
|
41
|
-
const root = mkdtempSync(path.join(tmpdir(), 'oxy-core-esm-fix-'));
|
|
42
|
-
try {
|
|
43
|
-
for (const [name, source] of Object.entries(files)) {
|
|
44
|
-
const full = path.join(root, name);
|
|
45
|
-
mkdirSync(path.dirname(full), { recursive: true });
|
|
46
|
-
writeFileSync(full, source);
|
|
47
|
-
}
|
|
48
|
-
const result = spawnSync(process.execPath, [script, root], { encoding: 'utf8' });
|
|
49
|
-
expect(result.status).toBe(0);
|
|
50
|
-
const out: Record<string, string> = {};
|
|
51
|
-
for (const name of Object.keys(files)) {
|
|
52
|
-
out[name] = readFileSync(path.join(root, name), 'utf8');
|
|
53
|
-
}
|
|
54
|
-
return out;
|
|
55
|
-
} finally {
|
|
56
|
-
rmSync(root, { recursive: true, force: true });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
describe('fix-esm-imports', () => {
|
|
61
|
-
it('adds .js to a dynamic relative import', () => {
|
|
62
|
-
const out = runOnFixture({
|
|
63
|
-
'server/workloadIdentity.js': 'export const canAttestWorkloadIdentity = () => true;\n',
|
|
64
|
-
'mixins/auth.js': [
|
|
65
|
-
'export async function canUse() {',
|
|
66
|
-
" const { canAttestWorkloadIdentity } = await import('../server/workloadIdentity');",
|
|
67
|
-
' return canAttestWorkloadIdentity();',
|
|
68
|
-
'}',
|
|
69
|
-
'',
|
|
70
|
-
].join('\n'),
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
expect(out['mixins/auth.js']).toContain("await import('../server/workloadIdentity.js')");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('rewrites every dynamic import in a file, not only the first', () => {
|
|
77
|
-
const out = runOnFixture({
|
|
78
|
-
'server/workloadIdentity.js': 'export const a = 1;\nexport const b = 2;\n',
|
|
79
|
-
'mixins/auth.js': [
|
|
80
|
-
"const first = await import('../server/workloadIdentity');",
|
|
81
|
-
"const second = await import('../server/workloadIdentity');",
|
|
82
|
-
'',
|
|
83
|
-
].join('\n'),
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const matches = out['mixins/auth.js'].match(/workloadIdentity\.js/g) ?? [];
|
|
87
|
-
expect(matches).toHaveLength(2);
|
|
88
|
-
// And nothing was left extensionless.
|
|
89
|
-
expect(out['mixins/auth.js']).not.toMatch(/workloadIdentity'/);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('tolerates whitespace between the keyword and the parenthesis', () => {
|
|
93
|
-
const out = runOnFixture({
|
|
94
|
-
'server/workloadIdentity.js': 'export const a = 1;\n',
|
|
95
|
-
'mixins/auth.js': "const m = await import(\n '../server/workloadIdentity'\n);\n",
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
expect(out['mixins/auth.js']).toContain("'../server/workloadIdentity.js'");
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('resolves a dynamic directory import to its index', () => {
|
|
102
|
-
const out = runOnFixture({
|
|
103
|
-
'server/index.js': 'export const a = 1;\n',
|
|
104
|
-
'mixins/auth.js': "const m = await import('../server');\n",
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
expect(out['mixins/auth.js']).toContain("'../server/index.js'");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('still rewrites the static forms, and leaves bare and already-suffixed specifiers alone', () => {
|
|
111
|
-
const out = runOnFixture({
|
|
112
|
-
'server/workloadIdentity.js': 'export const a = 1;\n',
|
|
113
|
-
'mixins/auth.js': [
|
|
114
|
-
"import { a } from '../server/workloadIdentity';",
|
|
115
|
-
"import '../server/workloadIdentity';",
|
|
116
|
-
"export { a as b } from '../server/workloadIdentity';",
|
|
117
|
-
"import { createHash } from 'node:crypto';",
|
|
118
|
-
"import { z } from 'zod';",
|
|
119
|
-
"const late = await import('./sibling.js');",
|
|
120
|
-
'',
|
|
121
|
-
].join('\n'),
|
|
122
|
-
'mixins/sibling.js': 'export const s = 1;\n',
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
const source = out['mixins/auth.js'];
|
|
126
|
-
expect(source.match(/workloadIdentity\.js/g) ?? []).toHaveLength(3);
|
|
127
|
-
expect(source).toContain("import { createHash } from 'node:crypto';");
|
|
128
|
-
expect(source).toContain("import { z } from 'zod';");
|
|
129
|
-
expect(source).toContain("await import('./sibling.js')");
|
|
130
|
-
expect(source).not.toContain('sibling.js.js');
|
|
131
|
-
});
|
|
132
|
-
});
|
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cancellation and timeout regressions.
|
|
3
|
-
*
|
|
4
|
-
* `HttpService` used to build its `AbortController` INSIDE the function
|
|
5
|
-
* `retryAsync` re-invokes, and link the caller's signal to each new controller
|
|
6
|
-
* with a bare `addEventListener`. Since `abort` is a once-only event, a signal
|
|
7
|
-
* that had already fired could not abort the controller built for attempt 2 —
|
|
8
|
-
* so a request the caller had CANCELLED was re-issued for real. A caller abort
|
|
9
|
-
* also reached the retry predicate as an `AbortError` carrying `status: 0`,
|
|
10
|
-
* which is not 4xx, so the predicate read it as a transient failure worth
|
|
11
|
-
* another try. With the 5s default timeout and 3 retries that is ~28s of work
|
|
12
|
-
* after the caller stopped waiting, inside a request queue ten slots deep.
|
|
13
|
-
*
|
|
14
|
-
* Every test here pins one half of "a cancellation is an instruction, not a
|
|
15
|
-
* failure": nothing retries it, nothing queues it, and nothing leaks after it.
|
|
16
|
-
*/
|
|
17
|
-
import { HttpService } from '../HttpService';
|
|
18
|
-
import { ErrorCodes } from '../utils/errorUtils';
|
|
19
|
-
|
|
20
|
-
function jsonResponse(data: unknown, status = 200): Response {
|
|
21
|
-
return new Response(JSON.stringify({ data }), {
|
|
22
|
-
status,
|
|
23
|
-
headers: { 'content-type': 'application/json' },
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* A fetch that never responds, but DOES honour its abort signal — rejecting
|
|
29
|
-
* with an `AbortError` exactly as the real one does.
|
|
30
|
-
*
|
|
31
|
-
* Honouring the signal is not harness politeness, it is the whole point: the
|
|
32
|
-
* behaviour under test is what happens after an abort, so a fake that ignores
|
|
33
|
-
* the signal would hang instead of exercising it.
|
|
34
|
-
*/
|
|
35
|
-
function hangingFetch(): { fetch: typeof globalThis.fetch; calls: () => number } {
|
|
36
|
-
let calls = 0;
|
|
37
|
-
return {
|
|
38
|
-
fetch: ((_input: RequestInfo | URL, init?: RequestInit) => {
|
|
39
|
-
calls++;
|
|
40
|
-
return new Promise<Response>((_resolve, reject) => {
|
|
41
|
-
const signal = init?.signal;
|
|
42
|
-
const fail = (): void => reject(new DOMException('The operation was aborted.', 'AbortError'));
|
|
43
|
-
if (!signal) return;
|
|
44
|
-
if (signal.aborted) { fail(); return; }
|
|
45
|
-
signal.addEventListener('abort', fail, { once: true });
|
|
46
|
-
});
|
|
47
|
-
}) as typeof globalThis.fetch,
|
|
48
|
-
calls: () => calls,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Pin the retry backoff's jitter to zero.
|
|
54
|
-
*
|
|
55
|
-
* `retryAsync`'s delay is `baseDelay * 2**attempt + Math.random() * 1000`, so
|
|
56
|
-
* with real timers a retry can land up to a second later. A test that waits a
|
|
57
|
-
* fixed 80ms to prove "no retry happened" would then pass whether the bug was
|
|
58
|
-
* present or not — it would just be measuring the jitter. Pinning it makes the
|
|
59
|
-
* retry window exactly `baseDelay * (1 + 2 + 4)`, which a short wait covers
|
|
60
|
-
* decisively.
|
|
61
|
-
*/
|
|
62
|
-
function pinJitter(): void {
|
|
63
|
-
jest.spyOn(Math, 'random').mockReturnValue(0);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
describe('HttpService cancellation', () => {
|
|
67
|
-
const originalFetch = globalThis.fetch;
|
|
68
|
-
|
|
69
|
-
afterEach(() => {
|
|
70
|
-
globalThis.fetch = originalFetch;
|
|
71
|
-
jest.restoreAllMocks();
|
|
72
|
-
jest.useRealTimers();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('never calls fetch for a signal that was already aborted', async () => {
|
|
76
|
-
let calls = 0;
|
|
77
|
-
globalThis.fetch = (async () => { calls++; return jsonResponse({}); }) as typeof globalThis.fetch;
|
|
78
|
-
|
|
79
|
-
const http = new HttpService({ baseURL: 'https://api.test' });
|
|
80
|
-
const controller = new AbortController();
|
|
81
|
-
controller.abort();
|
|
82
|
-
|
|
83
|
-
await expect(http.get('/thing', { signal: controller.signal })).rejects.toMatchObject({
|
|
84
|
-
code: ErrorCodes.CANCELLED,
|
|
85
|
-
});
|
|
86
|
-
expect(calls).toBe(0);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('issues exactly one fetch when a request is cancelled mid-flight, with retry on', async () => {
|
|
90
|
-
pinJitter();
|
|
91
|
-
const { fetch, calls } = hangingFetch();
|
|
92
|
-
globalThis.fetch = fetch;
|
|
93
|
-
|
|
94
|
-
const http = new HttpService({
|
|
95
|
-
baseURL: 'https://api.test',
|
|
96
|
-
enableRetry: true,
|
|
97
|
-
maxRetries: 3,
|
|
98
|
-
retryDelay: 1,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const controller = new AbortController();
|
|
102
|
-
const pending = http.get('/thing', { signal: controller.signal });
|
|
103
|
-
const assertion = expect(pending).rejects.toMatchObject({ code: ErrorCodes.CANCELLED });
|
|
104
|
-
|
|
105
|
-
// Let the request reach fetch, then cancel it.
|
|
106
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
107
|
-
expect(calls()).toBe(1);
|
|
108
|
-
controller.abort();
|
|
109
|
-
await assertion;
|
|
110
|
-
|
|
111
|
-
// The retry budget was 3 more attempts, whose backoff with jitter pinned is
|
|
112
|
-
// 1+2+4ms. Waiting well past that window is what proves none of them ran,
|
|
113
|
-
// and it is the crux of the defect: the re-issued request went out AFTER
|
|
114
|
-
// the rejection the caller saw, so a test that stopped at the rejection
|
|
115
|
-
// would have passed with the bug fully present.
|
|
116
|
-
await new Promise((resolve) => setTimeout(resolve, 80));
|
|
117
|
-
expect(calls()).toBe(1);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('leaves no abort listener on a caller signal that outlives the request', async () => {
|
|
121
|
-
globalThis.fetch = (async () => jsonResponse({ ok: true })) as typeof globalThis.fetch;
|
|
122
|
-
|
|
123
|
-
const controller = new AbortController();
|
|
124
|
-
const added: unknown[] = [];
|
|
125
|
-
const removed: unknown[] = [];
|
|
126
|
-
const realAdd = controller.signal.addEventListener.bind(controller.signal);
|
|
127
|
-
const realRemove = controller.signal.removeEventListener.bind(controller.signal);
|
|
128
|
-
jest.spyOn(controller.signal, 'addEventListener').mockImplementation(((type: string, fn: never, opts: never) => {
|
|
129
|
-
if (type === 'abort') added.push(fn);
|
|
130
|
-
return realAdd(type as 'abort', fn, opts);
|
|
131
|
-
}) as never);
|
|
132
|
-
jest.spyOn(controller.signal, 'removeEventListener').mockImplementation(((type: string, fn: never, opts: never) => {
|
|
133
|
-
if (type === 'abort') removed.push(fn);
|
|
134
|
-
return realRemove(type as 'abort', fn, opts);
|
|
135
|
-
}) as never);
|
|
136
|
-
|
|
137
|
-
const http = new HttpService({ baseURL: 'https://api.test' });
|
|
138
|
-
// A React Query query signal is reused across the query's whole lifetime,
|
|
139
|
-
// so a listener left behind per request is an unbounded leak, not a nit.
|
|
140
|
-
for (let i = 0; i < 5; i++) {
|
|
141
|
-
await http.get(`/thing-${i}`, { signal: controller.signal, cache: false, deduplicate: false });
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
expect(added.length).toBeGreaterThan(0);
|
|
145
|
-
expect(removed.length).toBe(added.length);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('does not consume a queue slot for a cancelled request, so a live one still runs', async () => {
|
|
149
|
-
const live: string[] = [];
|
|
150
|
-
globalThis.fetch = (async (input: RequestInfo | URL) => {
|
|
151
|
-
const url = String(input);
|
|
152
|
-
if (url.includes('/live')) {
|
|
153
|
-
live.push(url);
|
|
154
|
-
return jsonResponse({ ok: true });
|
|
155
|
-
}
|
|
156
|
-
// Cancelled requests never get here; if one does, it would hold a slot.
|
|
157
|
-
return new Promise<Response>(() => { /* never settles */ });
|
|
158
|
-
}) as typeof globalThis.fetch;
|
|
159
|
-
|
|
160
|
-
const http = new HttpService({
|
|
161
|
-
baseURL: 'https://api.test',
|
|
162
|
-
maxConcurrentRequests: 2,
|
|
163
|
-
enableRetry: false,
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// Fill more than the pool with requests whose callers have already gone.
|
|
167
|
-
const dead = Array.from({ length: 6 }, (_, i) => {
|
|
168
|
-
const controller = new AbortController();
|
|
169
|
-
controller.abort();
|
|
170
|
-
return http.get(`/dead-${i}`, { signal: controller.signal }).catch(() => 'cancelled');
|
|
171
|
-
});
|
|
172
|
-
await Promise.all(dead);
|
|
173
|
-
|
|
174
|
-
// With only two slots, this is the assertion that matters: the live request
|
|
175
|
-
// is not queued behind six abandoned ones.
|
|
176
|
-
await expect(http.get('/live', { cache: false })).resolves.toBeDefined();
|
|
177
|
-
expect(live).toHaveLength(1);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe('HttpService timeout', () => {
|
|
182
|
-
const originalFetch = globalThis.fetch;
|
|
183
|
-
|
|
184
|
-
afterEach(() => {
|
|
185
|
-
globalThis.fetch = originalFetch;
|
|
186
|
-
jest.restoreAllMocks();
|
|
187
|
-
jest.useRealTimers();
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('does not retry a timeout by default, and reports it as a timeout not a cancellation', async () => {
|
|
191
|
-
pinJitter();
|
|
192
|
-
const { fetch, calls } = hangingFetch();
|
|
193
|
-
globalThis.fetch = fetch;
|
|
194
|
-
|
|
195
|
-
const http = new HttpService({
|
|
196
|
-
baseURL: 'https://api.test',
|
|
197
|
-
enableRetry: true,
|
|
198
|
-
maxRetries: 3,
|
|
199
|
-
retryDelay: 1,
|
|
200
|
-
requestTimeout: 20,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
await expect(http.get('/slow', { cache: false })).rejects.toMatchObject({
|
|
204
|
-
code: ErrorCodes.TIMEOUT,
|
|
205
|
-
timeout: true,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
await new Promise((resolve) => setTimeout(resolve, 80));
|
|
209
|
-
// One attempt, not four. Four behind a short timeout is how a single slow
|
|
210
|
-
// endpoint used to cost tens of seconds of wall clock.
|
|
211
|
-
expect(calls()).toBe(1);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('retries a timeout when the caller opts in', async () => {
|
|
215
|
-
const { fetch, calls } = hangingFetch();
|
|
216
|
-
globalThis.fetch = fetch;
|
|
217
|
-
|
|
218
|
-
const http = new HttpService({
|
|
219
|
-
baseURL: 'https://api.test',
|
|
220
|
-
enableRetry: true,
|
|
221
|
-
maxRetries: 2,
|
|
222
|
-
retryDelay: 1,
|
|
223
|
-
requestTimeout: 20,
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
await expect(
|
|
227
|
-
http.get('/slow', { cache: false, retryOnTimeout: true }),
|
|
228
|
-
).rejects.toMatchObject({ code: ErrorCodes.TIMEOUT });
|
|
229
|
-
|
|
230
|
-
expect(calls()).toBe(3);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('bounds total wall clock with a deadline, even with retries on', async () => {
|
|
234
|
-
pinJitter();
|
|
235
|
-
const { fetch } = hangingFetch();
|
|
236
|
-
globalThis.fetch = fetch;
|
|
237
|
-
|
|
238
|
-
const http = new HttpService({
|
|
239
|
-
baseURL: 'https://api.test',
|
|
240
|
-
enableRetry: true,
|
|
241
|
-
maxRetries: 5,
|
|
242
|
-
retryDelay: 100,
|
|
243
|
-
requestTimeout: 20,
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
const started = Date.now();
|
|
247
|
-
await expect(
|
|
248
|
-
http.get('/slow', { cache: false, retryOnTimeout: true, deadline: 150 }),
|
|
249
|
-
).rejects.toBeDefined();
|
|
250
|
-
|
|
251
|
-
// `timeout` bounds an attempt; `deadline` bounds the call. Without it the
|
|
252
|
-
// total is attempts x timeout + backoff, which no call site computes.
|
|
253
|
-
expect(Date.now() - started).toBeLessThan(400);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it('still retries a 5xx — the fix must not disable retry wholesale', async () => {
|
|
257
|
-
let calls = 0;
|
|
258
|
-
globalThis.fetch = (async () => {
|
|
259
|
-
calls++;
|
|
260
|
-
return jsonResponse({ error: 'boom' }, 503);
|
|
261
|
-
}) as typeof globalThis.fetch;
|
|
262
|
-
|
|
263
|
-
const http = new HttpService({
|
|
264
|
-
baseURL: 'https://api.test',
|
|
265
|
-
enableRetry: true,
|
|
266
|
-
maxRetries: 2,
|
|
267
|
-
retryDelay: 1,
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
await expect(http.get('/flaky', { cache: false })).rejects.toBeDefined();
|
|
271
|
-
expect(calls).toBe(3);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it('still refuses to retry a 4xx', async () => {
|
|
275
|
-
let calls = 0;
|
|
276
|
-
globalThis.fetch = (async () => {
|
|
277
|
-
calls++;
|
|
278
|
-
return jsonResponse({ error: 'nope' }, 404);
|
|
279
|
-
}) as typeof globalThis.fetch;
|
|
280
|
-
|
|
281
|
-
const http = new HttpService({
|
|
282
|
-
baseURL: 'https://api.test',
|
|
283
|
-
enableRetry: true,
|
|
284
|
-
maxRetries: 3,
|
|
285
|
-
retryDelay: 1,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
await expect(http.get('/missing', { cache: false })).rejects.toBeDefined();
|
|
289
|
-
expect(calls).toBe(1);
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it('arms no timer past a request that threw before returning', async () => {
|
|
293
|
-
globalThis.fetch = (async () => jsonResponse({ error: 'nope' }, 404)) as typeof globalThis.fetch;
|
|
294
|
-
jest.useFakeTimers({ doNotFake: ['nextTick'] });
|
|
295
|
-
|
|
296
|
-
const http = new HttpService({
|
|
297
|
-
baseURL: 'https://api.test',
|
|
298
|
-
enableRetry: false,
|
|
299
|
-
requestTimeout: 30_000,
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
await expect(http.get('/missing', { cache: false })).rejects.toBeDefined();
|
|
303
|
-
// `clearTimeout` used to sit on the success path only, so any throw between
|
|
304
|
-
// the fetch and the return left a 30s timer armed.
|
|
305
|
-
expect(jest.getTimerCount()).toBe(0);
|
|
306
|
-
jest.useRealTimers();
|
|
307
|
-
});
|
|
308
|
-
});
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { HttpService } from '../HttpService';
|
|
2
|
-
|
|
3
|
-
describe('HttpService browser activity identifier', () => {
|
|
4
|
-
const originalFetch = globalThis.fetch;
|
|
5
|
-
const originalWindowDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'window');
|
|
6
|
-
const originalDocumentDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'document');
|
|
7
|
-
|
|
8
|
-
afterEach(() => {
|
|
9
|
-
globalThis.fetch = originalFetch;
|
|
10
|
-
if (originalWindowDescriptor) {
|
|
11
|
-
Object.defineProperty(globalThis, 'window', originalWindowDescriptor);
|
|
12
|
-
} else {
|
|
13
|
-
Reflect.deleteProperty(globalThis, 'window');
|
|
14
|
-
}
|
|
15
|
-
if (originalDocumentDescriptor) {
|
|
16
|
-
Object.defineProperty(globalThis, 'document', originalDocumentDescriptor);
|
|
17
|
-
} else {
|
|
18
|
-
Reflect.deleteProperty(globalThis, 'document');
|
|
19
|
-
}
|
|
20
|
-
jest.restoreAllMocks();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('adds the runtime identifier after caller headers', async () => {
|
|
24
|
-
Object.defineProperty(globalThis, 'window', {
|
|
25
|
-
configurable: true,
|
|
26
|
-
value: {},
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(globalThis, 'document', {
|
|
29
|
-
configurable: true,
|
|
30
|
-
value: {},
|
|
31
|
-
});
|
|
32
|
-
const fetchMock = jest.fn(async () => new Response(JSON.stringify({ data: { ok: true } }), {
|
|
33
|
-
status: 200,
|
|
34
|
-
headers: { 'content-type': 'application/json' },
|
|
35
|
-
}));
|
|
36
|
-
globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch;
|
|
37
|
-
|
|
38
|
-
const http = new HttpService({ baseURL: 'https://api.oxy.so', enableRetry: false });
|
|
39
|
-
await http.get('/session/status', {
|
|
40
|
-
headers: { 'X-Oxy-Activity-Id': 'caller-controlled' },
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const requestHeaders = fetchMock.mock.calls[0]?.[1]?.headers as Record<string, string>;
|
|
44
|
-
expect(requestHeaders['X-Oxy-Activity-Id']).toMatch(
|
|
45
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
|
|
46
|
-
);
|
|
47
|
-
expect(requestHeaders['X-Oxy-Activity-Id']).not.toBe('caller-controlled');
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth self-await regression.
|
|
3
|
-
*
|
|
4
|
-
* The refresh handler (arm 2 shared-key sign-in) calls PRE-SESSION public
|
|
5
|
-
* endpoints (`/auth/challenge`, `/auth/verify`, the commons-signin surface, …)
|
|
6
|
-
* from INSIDE the single-flight `tokenRefreshPromise`. If any of those carried
|
|
7
|
-
* an auth preflight (no `skipAuth`), its `getAuthHeader` would call
|
|
8
|
-
* `refreshAccessToken`, find the handler's own promise already in flight, and
|
|
9
|
-
* await it — the handler awaiting itself → permanent hang (no deadline on the
|
|
10
|
-
* auto-connect lane makes it visible). `skipAuth` on every pre-session public
|
|
11
|
-
* endpoint is what prevents this; these tests lock the invariant.
|
|
12
|
-
*/
|
|
13
|
-
import { HttpService } from '../HttpService';
|
|
14
|
-
|
|
15
|
-
function createJwt(payload: Record<string, unknown>): string {
|
|
16
|
-
const encode = (value: unknown): string => Buffer.from(JSON.stringify(value)).toString('base64url');
|
|
17
|
-
return `${encode({ alg: 'HS256', typ: 'JWT' })}.${encode(payload)}.signature`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function jsonResponse(data: unknown): Response {
|
|
21
|
-
return new Response(JSON.stringify({ data }), {
|
|
22
|
-
status: 200,
|
|
23
|
-
headers: { 'content-type': 'application/json' },
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const nowSec = (): number => Math.floor(Date.now() / 1000);
|
|
28
|
-
|
|
29
|
-
/** Resolve to `true` if `promise` settles within `ms`, else `false`. Always
|
|
30
|
-
* clears its timer so no pending timeout leaks into jest's teardown. */
|
|
31
|
-
async function settlesWithin(promise: Promise<unknown>, ms: number): Promise<boolean> {
|
|
32
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
33
|
-
const timeout = new Promise<false>((resolve) => {
|
|
34
|
-
timer = setTimeout(() => resolve(false), ms);
|
|
35
|
-
});
|
|
36
|
-
try {
|
|
37
|
-
return await Promise.race([promise.then(() => true), timeout]);
|
|
38
|
-
} finally {
|
|
39
|
-
clearTimeout(timer);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
describe('HttpService auth self-await', () => {
|
|
44
|
-
const originalFetch = globalThis.fetch;
|
|
45
|
-
|
|
46
|
-
afterEach(() => {
|
|
47
|
-
globalThis.fetch = originalFetch;
|
|
48
|
-
jest.restoreAllMocks();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('a skipAuth request issued from INSIDE the refresh handler resolves (no self-await)', async () => {
|
|
52
|
-
globalThis.fetch = (async (input: RequestInfo | URL) => {
|
|
53
|
-
const url = String(input);
|
|
54
|
-
if (url.includes('/auth/challenge')) return jsonResponse({ challenge: 'c' });
|
|
55
|
-
return jsonResponse({ ok: true });
|
|
56
|
-
}) as typeof fetch;
|
|
57
|
-
|
|
58
|
-
const http = new HttpService({ baseURL: 'https://api.oxy.so', enableRetry: false });
|
|
59
|
-
// Near-expiry → the data request's preflight starts the refresh.
|
|
60
|
-
http.setTokens(createJwt({ userId: 'u', exp: nowSec() + 30 }));
|
|
61
|
-
|
|
62
|
-
http.setAuthRefreshHandler(async () => {
|
|
63
|
-
// Mirror arm 2: from inside the handler, hit a pre-session public endpoint.
|
|
64
|
-
// With skipAuth it does NOT re-enter refreshAccessToken; without it, its
|
|
65
|
-
// preflight would await THIS handler's own pending promise → self-await.
|
|
66
|
-
await http.post('/auth/challenge', { publicKey: 'p' }, { skipAuth: true, retry: false });
|
|
67
|
-
const fresh = createJwt({ userId: 'u', exp: nowSec() + 3600, jti: 'fresh' });
|
|
68
|
-
http.setTokens(fresh);
|
|
69
|
-
return fresh;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
expect(await settlesWithin(http.get('/data'), 500)).toBe(true);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('a skipAuth public request does NOT await a pending refresh', async () => {
|
|
76
|
-
let releaseRefresh: (() => void) | undefined;
|
|
77
|
-
const refreshGate = new Promise<void>((resolve) => {
|
|
78
|
-
releaseRefresh = resolve;
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
globalThis.fetch = (async (input: RequestInfo | URL) => {
|
|
82
|
-
const url = String(input);
|
|
83
|
-
if (url.includes('/auth/challenge')) return jsonResponse({ challenge: 'c' });
|
|
84
|
-
return jsonResponse({ ok: true });
|
|
85
|
-
}) as typeof fetch;
|
|
86
|
-
|
|
87
|
-
const http = new HttpService({ baseURL: 'https://api.oxy.so', enableRetry: false });
|
|
88
|
-
http.setTokens(createJwt({ userId: 'u', exp: nowSec() + 30 }));
|
|
89
|
-
|
|
90
|
-
http.setAuthRefreshHandler(async () => {
|
|
91
|
-
await refreshGate; // hold the refresh open
|
|
92
|
-
const fresh = createJwt({ userId: 'u', exp: nowSec() + 3600, jti: 'fresh' });
|
|
93
|
-
http.setTokens(fresh);
|
|
94
|
-
return fresh;
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// A data request whose preflight starts (and blocks on) the held refresh.
|
|
98
|
-
const data = http.get('/data');
|
|
99
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
100
|
-
|
|
101
|
-
// A skipAuth public request must settle WITHOUT waiting for the held refresh.
|
|
102
|
-
const pub = http.post('/auth/challenge', { publicKey: 'p' }, { skipAuth: true, retry: false });
|
|
103
|
-
expect(await settlesWithin(pub, 300)).toBe(true);
|
|
104
|
-
|
|
105
|
-
releaseRefresh?.();
|
|
106
|
-
await data;
|
|
107
|
-
});
|
|
108
|
-
});
|