@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,180 +0,0 @@
|
|
|
1
|
-
import { normalizeProfileLinks, type ProfileLink } from '../profileLinks';
|
|
2
|
-
|
|
3
|
-
describe('normalizeProfileLinks', () => {
|
|
4
|
-
describe('linksMetadata path (preferred)', () => {
|
|
5
|
-
it('maps title + url and uses the entry id when present', () => {
|
|
6
|
-
const result = normalizeProfileLinks([
|
|
7
|
-
{ url: 'https://oxy.so', title: 'Oxy', id: 'abc' },
|
|
8
|
-
]);
|
|
9
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
10
|
-
{ id: 'abc', title: 'Oxy', url: 'https://oxy.so' },
|
|
11
|
-
]);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('falls back to the index when an entry has no id', () => {
|
|
15
|
-
const result = normalizeProfileLinks([
|
|
16
|
-
{ url: 'https://a.example', title: 'A' },
|
|
17
|
-
{ url: 'https://b.example', title: 'B' },
|
|
18
|
-
]);
|
|
19
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
20
|
-
{ id: '0', title: 'A', url: 'https://a.example' },
|
|
21
|
-
{ id: '1', title: 'B', url: 'https://b.example' },
|
|
22
|
-
]);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('omits title when absent', () => {
|
|
26
|
-
const result = normalizeProfileLinks([{ url: 'https://no-title.example' }]);
|
|
27
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
28
|
-
{ id: '0', url: 'https://no-title.example' },
|
|
29
|
-
]);
|
|
30
|
-
expect(result[0]).not.toHaveProperty('title');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('carries through description and image when present', () => {
|
|
34
|
-
const result = normalizeProfileLinks([
|
|
35
|
-
{
|
|
36
|
-
url: 'https://oxy.so',
|
|
37
|
-
title: 'Oxy',
|
|
38
|
-
description: 'The Oxy ecosystem',
|
|
39
|
-
image: 'https://cdn.example/oxy.png',
|
|
40
|
-
id: 'abc',
|
|
41
|
-
},
|
|
42
|
-
]);
|
|
43
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
44
|
-
{
|
|
45
|
-
id: 'abc',
|
|
46
|
-
title: 'Oxy',
|
|
47
|
-
url: 'https://oxy.so',
|
|
48
|
-
description: 'The Oxy ecosystem',
|
|
49
|
-
image: 'https://cdn.example/oxy.png',
|
|
50
|
-
},
|
|
51
|
-
]);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('omits description and image when absent', () => {
|
|
55
|
-
const result = normalizeProfileLinks([
|
|
56
|
-
{ url: 'https://min.example', title: 'Min' },
|
|
57
|
-
]);
|
|
58
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
59
|
-
{ id: '0', title: 'Min', url: 'https://min.example' },
|
|
60
|
-
]);
|
|
61
|
-
expect(result[0]).not.toHaveProperty('description');
|
|
62
|
-
expect(result[0]).not.toHaveProperty('image');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('carries description and image independently of title', () => {
|
|
66
|
-
const result = normalizeProfileLinks([
|
|
67
|
-
{ url: 'https://only-image.example', image: 'https://cdn.example/i.png' },
|
|
68
|
-
{ url: 'https://only-desc.example', description: 'Just a description' },
|
|
69
|
-
]);
|
|
70
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
71
|
-
{ id: '0', url: 'https://only-image.example', image: 'https://cdn.example/i.png' },
|
|
72
|
-
{ id: '1', url: 'https://only-desc.example', description: 'Just a description' },
|
|
73
|
-
]);
|
|
74
|
-
expect(result[0]).not.toHaveProperty('title');
|
|
75
|
-
expect(result[0]).not.toHaveProperty('description');
|
|
76
|
-
expect(result[1]).not.toHaveProperty('title');
|
|
77
|
-
expect(result[1]).not.toHaveProperty('image');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('drops entries with missing or empty url and keeps stable index ids', () => {
|
|
81
|
-
const result = normalizeProfileLinks([
|
|
82
|
-
{ url: 'https://keep.example', title: 'Keep', id: 'keep' },
|
|
83
|
-
{ url: '', title: 'Empty' },
|
|
84
|
-
{ url: ' ', title: 'Whitespace' },
|
|
85
|
-
{ url: 'https://second.example', title: 'Second' },
|
|
86
|
-
]);
|
|
87
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
88
|
-
{ id: 'keep', title: 'Keep', url: 'https://keep.example' },
|
|
89
|
-
// index is preserved from the source array position (3), not re-numbered
|
|
90
|
-
{ id: '3', title: 'Second', url: 'https://second.example' },
|
|
91
|
-
]);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('trims surrounding whitespace from urls', () => {
|
|
95
|
-
const result = normalizeProfileLinks([{ url: ' https://trim.example ' }]);
|
|
96
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
97
|
-
{ id: '0', url: 'https://trim.example' },
|
|
98
|
-
]);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('does NOT add a scheme to bare urls', () => {
|
|
102
|
-
const result = normalizeProfileLinks([{ url: 'oxy.so', title: 'Bare' }]);
|
|
103
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
104
|
-
{ id: '0', title: 'Bare', url: 'oxy.so' },
|
|
105
|
-
]);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('legacy links path (no linksMetadata)', () => {
|
|
110
|
-
it('maps strings to { id, url } without title/description/image', () => {
|
|
111
|
-
const result = normalizeProfileLinks(undefined, [
|
|
112
|
-
'https://a.example',
|
|
113
|
-
'https://b.example',
|
|
114
|
-
]);
|
|
115
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
116
|
-
{ id: '0', url: 'https://a.example' },
|
|
117
|
-
{ id: '1', url: 'https://b.example' },
|
|
118
|
-
]);
|
|
119
|
-
expect(
|
|
120
|
-
result.every(
|
|
121
|
-
(link) =>
|
|
122
|
-
!('title' in link) &&
|
|
123
|
-
!('description' in link) &&
|
|
124
|
-
!('image' in link),
|
|
125
|
-
),
|
|
126
|
-
).toBe(true);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('drops empty and whitespace-only strings, preserving source index ids', () => {
|
|
130
|
-
const result = normalizeProfileLinks(undefined, [
|
|
131
|
-
'https://keep.example',
|
|
132
|
-
'',
|
|
133
|
-
' ',
|
|
134
|
-
'https://second.example',
|
|
135
|
-
]);
|
|
136
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
137
|
-
{ id: '0', url: 'https://keep.example' },
|
|
138
|
-
{ id: '3', url: 'https://second.example' },
|
|
139
|
-
]);
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
describe('fall-through and empty inputs', () => {
|
|
144
|
-
it('returns [] when both inputs are absent', () => {
|
|
145
|
-
expect(normalizeProfileLinks()).toEqual([]);
|
|
146
|
-
expect(normalizeProfileLinks(undefined, undefined)).toEqual([]);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('returns [] when both inputs are empty arrays', () => {
|
|
150
|
-
expect(normalizeProfileLinks([], [])).toEqual([]);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it('falls through to legacy links when linksMetadata is empty', () => {
|
|
154
|
-
const result = normalizeProfileLinks([], ['https://legacy.example']);
|
|
155
|
-
expect(result).toEqual<ProfileLink[]>([
|
|
156
|
-
{ id: '0', url: 'https://legacy.example' },
|
|
157
|
-
]);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('returns [] (does NOT fall back to links) when linksMetadata is non-empty but every entry is dropped', () => {
|
|
161
|
-
const result = normalizeProfileLinks(
|
|
162
|
-
[{ url: '' }, { url: ' ' }],
|
|
163
|
-
['https://legacy.example'],
|
|
164
|
-
);
|
|
165
|
-
expect(result).toEqual([]);
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('is pure — does not mutate its inputs', () => {
|
|
170
|
-
const linksMetadata = [{ url: 'https://oxy.so', title: 'Oxy', id: 'abc' }];
|
|
171
|
-
const links = ['https://legacy.example'];
|
|
172
|
-
const metadataSnapshot = JSON.stringify(linksMetadata);
|
|
173
|
-
const linksSnapshot = JSON.stringify(links);
|
|
174
|
-
|
|
175
|
-
normalizeProfileLinks(linksMetadata, links);
|
|
176
|
-
|
|
177
|
-
expect(JSON.stringify(linksMetadata)).toBe(metadataSnapshot);
|
|
178
|
-
expect(JSON.stringify(links)).toBe(linksSnapshot);
|
|
179
|
-
});
|
|
180
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `redactUrlQuery` tests — the query-string scrubber used before any asset URL
|
|
3
|
-
* reaches a log sink. Asset stream URLs carry a scoped `mt=` media token that
|
|
4
|
-
* is a bearer credential; it must never be logged.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { redactUrlQuery } from '../redactUrl';
|
|
8
|
-
|
|
9
|
-
describe('redactUrlQuery', () => {
|
|
10
|
-
it('strips the query string (including a media token) from an absolute URL', () => {
|
|
11
|
-
const redacted = redactUrlQuery(
|
|
12
|
-
'https://api.oxy.so/assets/priv1/stream?variant=thumb&mt=SECRET-TOKEN',
|
|
13
|
-
);
|
|
14
|
-
expect(redacted).toBe('https://api.oxy.so/assets/priv1/stream?<redacted>');
|
|
15
|
-
expect(redacted).not.toContain('mt=');
|
|
16
|
-
expect(redacted).not.toContain('SECRET-TOKEN');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('strips the query string from a relative path too', () => {
|
|
20
|
-
expect(redactUrlQuery('/assets/priv1/url?expiresIn=600&mt=SECRET')).toBe(
|
|
21
|
-
'/assets/priv1/url?<redacted>',
|
|
22
|
-
);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('returns a URL without a query string unchanged', () => {
|
|
26
|
-
expect(redactUrlQuery('https://cloud.oxy.so/pub1')).toBe('https://cloud.oxy.so/pub1');
|
|
27
|
-
expect(redactUrlQuery('/assets')).toBe('/assets');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('passes through empty input', () => {
|
|
31
|
-
expect(redactUrlQuery('')).toBe('');
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `registrableApex` — the eTLD+1 host kernel (Public Suffix List aware).
|
|
3
|
-
*
|
|
4
|
-
* The client `autoDetectAuthWebUrl` helper was removed in the device-first
|
|
5
|
-
* cutover; only the registrable-apex kernel survives (used by the api SSO
|
|
6
|
-
* surface + the IdP). These cases lock its Public-Suffix-List behaviour.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { registrableApex } from '../registrableApex';
|
|
10
|
-
|
|
11
|
-
describe('registrableApex', () => {
|
|
12
|
-
it('returns the eTLD+1 for a normal two-label host', () => {
|
|
13
|
-
expect(registrableApex('mention.earth')).toBe('mention.earth');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('strips subdomains down to the trailing two labels', () => {
|
|
17
|
-
expect(registrableApex('www.mention.earth')).toBe('mention.earth');
|
|
18
|
-
expect(registrableApex('deep.app.homiio.com')).toBe('homiio.com');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('lower-cases the input', () => {
|
|
22
|
-
expect(registrableApex('WWW.Mention.EARTH')).toBe('mention.earth');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('returns the eTLD+1 for hosts under multi-part public suffixes', () => {
|
|
26
|
-
expect(registrableApex('foo.co.uk')).toBe('foo.co.uk');
|
|
27
|
-
expect(registrableApex('www.foo.co.uk')).toBe('foo.co.uk');
|
|
28
|
-
expect(registrableApex('shop.victim.com.tr')).toBe('victim.com.tr');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('returns the eTLD+1 for hosts under private hosted suffixes', () => {
|
|
32
|
-
expect(registrableApex('honest.github.io')).toBe('honest.github.io');
|
|
33
|
-
expect(registrableApex('app.victim.pages.dev')).toBe('victim.pages.dev');
|
|
34
|
-
expect(registrableApex('site.victim.netlify.app')).toBe('victim.netlify.app');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('returns null for bare public and private suffixes', () => {
|
|
38
|
-
expect(registrableApex('co.uk')).toBeNull();
|
|
39
|
-
expect(registrableApex('github.io')).toBeNull();
|
|
40
|
-
expect(registrableApex('pages.dev')).toBeNull();
|
|
41
|
-
expect(registrableApex('netlify.app')).toBeNull();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('returns null for IPv4 literals', () => {
|
|
45
|
-
expect(registrableApex('192.168.1.10')).toBeNull();
|
|
46
|
-
expect(registrableApex('10.0.0.1')).toBeNull();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('returns null for IPv6 literals and hosts carrying a port', () => {
|
|
50
|
-
expect(registrableApex('[::1]')).toBeNull();
|
|
51
|
-
expect(registrableApex('mention.earth:3000')).toBeNull();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('returns null for single-label hosts', () => {
|
|
55
|
-
expect(registrableApex('intranet')).toBeNull();
|
|
56
|
-
expect(registrableApex('localhost')).toBeNull();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('returns null for empty input', () => {
|
|
60
|
-
expect(registrableApex('')).toBeNull();
|
|
61
|
-
});
|
|
62
|
-
});
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Abort awareness in the request queue and the deduplicator.
|
|
3
|
-
*
|
|
4
|
-
* Neither used to know about cancellation, and each turned that into a
|
|
5
|
-
* different bug:
|
|
6
|
-
*
|
|
7
|
-
* - `RequestQueue` never dropped a queued entry whose caller had cancelled, so
|
|
8
|
-
* a burst of abandoned work (a search box being typed into) occupied every
|
|
9
|
-
* one of the ten slots while the ONE request the viewer was waiting on
|
|
10
|
-
* queued behind it. Refusing to RETRY a cancellation stops making more
|
|
11
|
-
* zombies; this is what returns the slots.
|
|
12
|
-
* - `RequestDeduplicator` handed every caller on a key the same promise, so one
|
|
13
|
-
* caller's abort rejected all the others — including ones that never
|
|
14
|
-
* cancelled anything and had no way to know the failure was not theirs.
|
|
15
|
-
*/
|
|
16
|
-
import { RequestDeduplicator, RequestQueue } from '../requestUtils';
|
|
17
|
-
import { ErrorCodes } from '../errorUtils';
|
|
18
|
-
|
|
19
|
-
const aborted = (): AbortSignal => {
|
|
20
|
-
const controller = new AbortController();
|
|
21
|
-
controller.abort();
|
|
22
|
-
return controller.signal;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
describe('RequestQueue abort awareness', () => {
|
|
26
|
-
it('never runs a request whose caller already cancelled', async () => {
|
|
27
|
-
const queue = new RequestQueue(2);
|
|
28
|
-
const run = jest.fn(async () => 'ran');
|
|
29
|
-
|
|
30
|
-
await expect(queue.enqueue(run, aborted())).rejects.toMatchObject({
|
|
31
|
-
code: ErrorCodes.CANCELLED,
|
|
32
|
-
});
|
|
33
|
-
expect(run).not.toHaveBeenCalled();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('keeps slots free for a live request when the queue is full of cancelled ones', async () => {
|
|
37
|
-
const queue = new RequestQueue(2);
|
|
38
|
-
let liveRan = false;
|
|
39
|
-
|
|
40
|
-
// Six abandoned requests against a two-slot pool. If any of them took a
|
|
41
|
-
// slot and held it, the live request below could never run.
|
|
42
|
-
const dead = Array.from({ length: 6 }, () =>
|
|
43
|
-
queue
|
|
44
|
-
.enqueue(() => new Promise<string>(() => { /* would never settle */ }), aborted())
|
|
45
|
-
.catch(() => 'cancelled'),
|
|
46
|
-
);
|
|
47
|
-
await Promise.all(dead);
|
|
48
|
-
|
|
49
|
-
await expect(
|
|
50
|
-
queue.enqueue(async () => { liveRan = true; return 'live'; }),
|
|
51
|
-
).resolves.toBe('live');
|
|
52
|
-
expect(liveRan).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('drops a queued entry that is cancelled while it waits for a slot', async () => {
|
|
56
|
-
const queue = new RequestQueue(1);
|
|
57
|
-
const started: string[] = [];
|
|
58
|
-
let releaseFirst: (() => void) | undefined;
|
|
59
|
-
|
|
60
|
-
const first = queue.enqueue(async () => {
|
|
61
|
-
started.push('first');
|
|
62
|
-
await new Promise<void>((resolve) => { releaseFirst = resolve; });
|
|
63
|
-
return 'first';
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// The pool is full, so this one sits in the queue rather than starting.
|
|
67
|
-
const controller = new AbortController();
|
|
68
|
-
const second = queue.enqueue(async () => {
|
|
69
|
-
started.push('second');
|
|
70
|
-
return 'second';
|
|
71
|
-
}, controller.signal);
|
|
72
|
-
|
|
73
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
74
|
-
expect(started).toEqual(['first']);
|
|
75
|
-
|
|
76
|
-
// Cancelled while queued: it must never start, not merely be ignored once
|
|
77
|
-
// it finishes. A request can sit here as long as the slots stay busy, which
|
|
78
|
-
// is exactly when the caller is most likely to have moved on.
|
|
79
|
-
controller.abort();
|
|
80
|
-
await expect(second).rejects.toMatchObject({ code: ErrorCodes.CANCELLED });
|
|
81
|
-
|
|
82
|
-
releaseFirst?.();
|
|
83
|
-
await expect(first).resolves.toBe('first');
|
|
84
|
-
expect(started).toEqual(['first']);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('still decrements its running count when a started request is aborted', async () => {
|
|
88
|
-
const queue = new RequestQueue(1);
|
|
89
|
-
const controller = new AbortController();
|
|
90
|
-
|
|
91
|
-
// An entry that has already started is left to its own abort domain: the
|
|
92
|
-
// queue must still observe it finishing, or `running` never comes back down
|
|
93
|
-
// and the slot is leaked permanently.
|
|
94
|
-
const inflight = queue.enqueue(
|
|
95
|
-
() => new Promise<string>((_resolve, reject) => {
|
|
96
|
-
controller.signal.addEventListener('abort', () => reject(new Error('aborted')), { once: true });
|
|
97
|
-
}),
|
|
98
|
-
controller.signal,
|
|
99
|
-
);
|
|
100
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
101
|
-
controller.abort();
|
|
102
|
-
await expect(inflight).rejects.toBeDefined();
|
|
103
|
-
|
|
104
|
-
await expect(queue.enqueue(async () => 'after')).resolves.toBe('after');
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe('RequestDeduplicator abort awareness', () => {
|
|
109
|
-
it('shares one in-flight request across callers', async () => {
|
|
110
|
-
const dedupe = new RequestDeduplicator();
|
|
111
|
-
const work = jest.fn(async () => {
|
|
112
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
113
|
-
return 'shared';
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const [a, b] = await Promise.all([
|
|
117
|
-
dedupe.deduplicate('key', work),
|
|
118
|
-
dedupe.deduplicate('key', work),
|
|
119
|
-
]);
|
|
120
|
-
|
|
121
|
-
expect(a).toBe('shared');
|
|
122
|
-
expect(b).toBe('shared');
|
|
123
|
-
expect(work).toHaveBeenCalledTimes(1);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('lets one caller cancel without rejecting the others', async () => {
|
|
127
|
-
const dedupe = new RequestDeduplicator();
|
|
128
|
-
const work = jest.fn(async () => {
|
|
129
|
-
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
130
|
-
return 'shared';
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const cancelling = new AbortController();
|
|
134
|
-
const first = dedupe.deduplicate('key', work, cancelling.signal);
|
|
135
|
-
const second = dedupe.deduplicate('key', work, new AbortController().signal);
|
|
136
|
-
|
|
137
|
-
const firstAssertion = expect(first).rejects.toMatchObject({ code: ErrorCodes.CANCELLED });
|
|
138
|
-
cancelling.abort();
|
|
139
|
-
await firstAssertion;
|
|
140
|
-
|
|
141
|
-
// The caller that never cancelled anything still gets its answer.
|
|
142
|
-
await expect(second).resolves.toBe('shared');
|
|
143
|
-
expect(work).toHaveBeenCalledTimes(1);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('refuses a caller whose signal is already aborted without starting work', async () => {
|
|
147
|
-
const dedupe = new RequestDeduplicator();
|
|
148
|
-
const work = jest.fn(async () => 'shared');
|
|
149
|
-
|
|
150
|
-
await expect(dedupe.deduplicate('key', work, aborted())).rejects.toMatchObject({
|
|
151
|
-
code: ErrorCodes.CANCELLED,
|
|
152
|
-
});
|
|
153
|
-
expect(work).not.toHaveBeenCalled();
|
|
154
|
-
});
|
|
155
|
-
});
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { normalizeInlineText, normalizeMultilineText } from '../textNormalization';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Whitespace characters are built from their code points rather than pasted as
|
|
5
|
-
* literals: an NBSP or a U+2028 in the source would be invisible to a reviewer
|
|
6
|
-
* and trivially "fixed" by an editor, silently gutting the test it anchors.
|
|
7
|
-
*/
|
|
8
|
-
const NBSP = String.fromCharCode(0x00a0); // no-break space
|
|
9
|
-
const EN_QUAD = String.fromCharCode(0x2000); // U+2000 space block
|
|
10
|
-
const IDEOGRAPHIC_SPACE = String.fromCharCode(0x3000); // CJK full-width space
|
|
11
|
-
const NARROW_NBSP = String.fromCharCode(0x202f);
|
|
12
|
-
const ZWNBSP = String.fromCharCode(0xfeff); // BOM when leading
|
|
13
|
-
const LINE_SEPARATOR = String.fromCharCode(0x2028);
|
|
14
|
-
const PARAGRAPH_SEPARATOR = String.fromCharCode(0x2029);
|
|
15
|
-
|
|
16
|
-
/** "é" as a base letter plus a combining acute accent (NFD form). */
|
|
17
|
-
const DECOMPOSED_E_ACUTE = `e${String.fromCharCode(0x0301)}`;
|
|
18
|
-
/** The precomposed "é" (NFC form) the two above must normalize into. */
|
|
19
|
-
const COMPOSED_E_ACUTE = String.fromCharCode(0x00e9);
|
|
20
|
-
|
|
21
|
-
describe('normalizeInlineText', () => {
|
|
22
|
-
it('flattens the indented multi-line <title> that caused the original bug', () => {
|
|
23
|
-
expect(normalizeInlineText('\n Mi título\n ')).toBe('Mi título');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('collapses every whitespace form to a single space', () => {
|
|
27
|
-
expect(normalizeInlineText('a\tb\nc\r\nd e')).toBe('a b c d e');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('collapses Unicode spaces (NBSP, U+2000 block, ideographic, narrow NBSP)', () => {
|
|
31
|
-
expect(
|
|
32
|
-
normalizeInlineText(`a${NBSP}b${EN_QUAD}c${IDEOGRAPHIC_SPACE}d${NARROW_NBSP}e`)
|
|
33
|
-
).toBe('a b c d e');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('collapses the Unicode line and paragraph separators', () => {
|
|
37
|
-
expect(normalizeInlineText(`a${LINE_SEPARATOR}b${PARAGRAPH_SEPARATOR}c`)).toBe('a b c');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('strips a leading BOM / zero-width no-break space', () => {
|
|
41
|
-
expect(normalizeInlineText(`${ZWNBSP}Título`)).toBe('Título');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('handles CRLF line endings', () => {
|
|
45
|
-
expect(normalizeInlineText('News\r\n\r\nToday')).toBe('News Today');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('returns an empty string for empty and whitespace-only input', () => {
|
|
49
|
-
expect(normalizeInlineText('')).toBe('');
|
|
50
|
-
expect(normalizeInlineText(' ')).toBe('');
|
|
51
|
-
expect(normalizeInlineText(`\n\t ${NBSP}\r\n`)).toBe('');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('NFC-normalizes so decomposed accents are stored composed', () => {
|
|
55
|
-
const normalized = normalizeInlineText(`Ren${DECOMPOSED_E_ACUTE}e`);
|
|
56
|
-
expect(normalized).toBe(`Ren${COMPOSED_E_ACUTE}e`);
|
|
57
|
-
expect(normalized).toHaveLength(5);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('leaves already-clean text untouched', () => {
|
|
61
|
-
expect(normalizeInlineText('Hacker News')).toBe('Hacker News');
|
|
62
|
-
expect(normalizeInlineText('Título en español — con guion')).toBe(
|
|
63
|
-
'Título en español — con guion'
|
|
64
|
-
);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('does not truncate long values (length caps are a product rule)', () => {
|
|
68
|
-
const long = 'a'.repeat(500);
|
|
69
|
-
expect(normalizeInlineText(long)).toHaveLength(500);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('does not strip markup or punctuation (that is the sanitizer\'s job)', () => {
|
|
73
|
-
expect(normalizeInlineText(' <b>Bold</b> & "quoted" ')).toBe('<b>Bold</b> & "quoted"');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('is idempotent', () => {
|
|
77
|
-
const inputs = [
|
|
78
|
-
'\n Mi título\n ',
|
|
79
|
-
`a${NBSP}${NBSP}b`,
|
|
80
|
-
'Hacker News',
|
|
81
|
-
'',
|
|
82
|
-
' ',
|
|
83
|
-
`Ren${DECOMPOSED_E_ACUTE}e`,
|
|
84
|
-
];
|
|
85
|
-
for (const input of inputs) {
|
|
86
|
-
const once = normalizeInlineText(input);
|
|
87
|
-
expect(normalizeInlineText(once)).toBe(once);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe('normalizeMultilineText', () => {
|
|
93
|
-
it('preserves the author\'s paragraphs', () => {
|
|
94
|
-
const body = 'First paragraph.\n\nSecond paragraph.\nSame paragraph, next line.';
|
|
95
|
-
expect(normalizeMultilineText(body)).toBe(body);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('collapses a blank line that contains spaces — the ordering bug', () => {
|
|
99
|
-
// The "blank" lines hold spaces, so they break the run of \n characters: a
|
|
100
|
-
// bare /\n{3,}/ collapse never sees them. Trailing horizontal whitespace
|
|
101
|
-
// must be stripped FIRST.
|
|
102
|
-
expect(normalizeMultilineText('a\n \n \nb')).toBe('a\n\nb');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('collapses a blank line that contains tabs and NBSP', () => {
|
|
106
|
-
expect(normalizeMultilineText(`a\n\t\n${NBSP}${NBSP}\nb`)).toBe('a\n\nb');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('strips trailing horizontal whitespace from every line', () => {
|
|
110
|
-
expect(normalizeMultilineText('one \ntwo\t\nthree ')).toBe('one\ntwo\nthree');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('collapses three or more newlines to a single blank line', () => {
|
|
114
|
-
expect(normalizeMultilineText('a\n\n\n\n\nb')).toBe('a\n\nb');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('keeps exactly one blank line as-is', () => {
|
|
118
|
-
expect(normalizeMultilineText('a\n\nb')).toBe('a\n\nb');
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('collapses runs of horizontal whitespace to one space, keeping newlines', () => {
|
|
122
|
-
expect(normalizeMultilineText('hello world\nsecond\t\tline')).toBe(
|
|
123
|
-
'hello world\nsecond line'
|
|
124
|
-
);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('strips leading horizontal whitespace from every line', () => {
|
|
128
|
-
expect(normalizeMultilineText('a\n b')).toBe('a\nb');
|
|
129
|
-
expect(normalizeMultilineText('one\n\ttwo\n three')).toBe('one\ntwo\nthree');
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('leaves no indent residue after a space-filled blank line', () => {
|
|
133
|
-
// The blank line collapses AND the six-space indent goes away entirely —
|
|
134
|
-
// collapsing it to a single space would leave a visible artifact under
|
|
135
|
-
// `white-space: pre-wrap`.
|
|
136
|
-
expect(normalizeMultilineText('Hola\n \n\n Mundo')).toBe('Hola\n\nMundo');
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('normalizes CRLF and lone CR to \\n', () => {
|
|
140
|
-
expect(normalizeMultilineText('a\r\nb\rc')).toBe('a\nb\nc');
|
|
141
|
-
expect(normalizeMultilineText('a\r\n\r\n\r\n\r\nb')).toBe('a\n\nb');
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('normalizes the Unicode line and paragraph separators to \\n', () => {
|
|
145
|
-
expect(normalizeMultilineText(`a${LINE_SEPARATOR}b${PARAGRAPH_SEPARATOR}c`)).toBe('a\nb\nc');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('collapses Unicode spaces without touching line structure', () => {
|
|
149
|
-
expect(normalizeMultilineText(`a${NBSP}${NBSP}b\nc${IDEOGRAPHIC_SPACE}d`)).toBe('a b\nc d');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('trims both ends, including leading and trailing blank lines', () => {
|
|
153
|
-
expect(normalizeMultilineText('\n\n Hello\n\nWorld \n\n ')).toBe('Hello\n\nWorld');
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('returns an empty string for empty and whitespace-only input', () => {
|
|
157
|
-
expect(normalizeMultilineText('')).toBe('');
|
|
158
|
-
expect(normalizeMultilineText(' ')).toBe('');
|
|
159
|
-
expect(normalizeMultilineText(`\n\n \t${NBSP}\r\n \n`)).toBe('');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('NFC-normalizes so decomposed accents are stored composed', () => {
|
|
163
|
-
expect(normalizeMultilineText(`Caf${DECOMPOSED_E_ACUTE}\n\nabierto`)).toBe(
|
|
164
|
-
`Caf${COMPOSED_E_ACUTE}\n\nabierto`
|
|
165
|
-
);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('leaves an already-clean body untouched', () => {
|
|
169
|
-
const body = 'Line one\nLine two\n\nNew paragraph.';
|
|
170
|
-
expect(normalizeMultilineText(body)).toBe(body);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('cleans a realistic federated post body without losing its paragraphs', () => {
|
|
174
|
-
const federated = ' Hola a todos.\r\n \r\n\r\nEsto es una prueba.\t\r\nFin. ';
|
|
175
|
-
expect(normalizeMultilineText(federated)).toBe(
|
|
176
|
-
'Hola a todos.\n\nEsto es una prueba.\nFin.'
|
|
177
|
-
);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('is idempotent', () => {
|
|
181
|
-
const inputs = [
|
|
182
|
-
'a\n \n \nb',
|
|
183
|
-
'a\r\n\r\n\r\nb',
|
|
184
|
-
'First paragraph.\n\nSecond paragraph.',
|
|
185
|
-
`a${NBSP}b`,
|
|
186
|
-
'a\n b',
|
|
187
|
-
'Hola\n \n\n Mundo',
|
|
188
|
-
'',
|
|
189
|
-
' ',
|
|
190
|
-
`Caf${DECOMPOSED_E_ACUTE}`,
|
|
191
|
-
];
|
|
192
|
-
for (const input of inputs) {
|
|
193
|
-
const once = normalizeMultilineText(input);
|
|
194
|
-
expect(normalizeMultilineText(once)).toBe(once);
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
describe('choosing between the two helpers', () => {
|
|
200
|
-
it('inline flattens what multiline preserves', () => {
|
|
201
|
-
const body = 'Title\n\nSubtitle';
|
|
202
|
-
expect(normalizeInlineText(body)).toBe('Title Subtitle');
|
|
203
|
-
expect(normalizeMultilineText(body)).toBe('Title\n\nSubtitle');
|
|
204
|
-
});
|
|
205
|
-
});
|