@oxy.so/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +16 -0
- package/README.md +221 -0
- package/dist/cjs/.tsbuildinfo +1 -0
- package/dist/cjs/HttpService.js +1270 -0
- package/dist/cjs/OxyServices.base.js +390 -0
- package/dist/cjs/OxyServices.errors.js +95 -0
- package/dist/cjs/OxyServices.js +72 -0
- package/dist/cjs/boot/sessionColdBoot.js +395 -0
- package/dist/cjs/constants/version.js +16 -0
- package/dist/cjs/crypto/aead.js +79 -0
- package/dist/cjs/crypto/ecdh.js +35 -0
- package/dist/cjs/crypto/identityMarker.js +255 -0
- package/dist/cjs/crypto/kdf.js +39 -0
- package/dist/cjs/crypto/keyManager.js +2234 -0
- package/dist/cjs/crypto/polyfill.js +131 -0
- package/dist/cjs/crypto/recoveryPhrase.js +242 -0
- package/dist/cjs/crypto/signatureService.js +273 -0
- package/dist/cjs/i18n/accountCategoryLabels.js +44 -0
- package/dist/cjs/i18n/accountRoleLabels.js +27 -0
- package/dist/cjs/i18n/index.js +90 -0
- package/dist/cjs/i18n/locales/ar-SA.json +282 -0
- package/dist/cjs/i18n/locales/ca-ES.json +282 -0
- package/dist/cjs/i18n/locales/de-DE.json +282 -0
- package/dist/cjs/i18n/locales/en-US.json +2161 -0
- package/dist/cjs/i18n/locales/es-ES.json +2161 -0
- package/dist/cjs/i18n/locales/fr-FR.json +282 -0
- package/dist/cjs/i18n/locales/it-IT.json +282 -0
- package/dist/cjs/i18n/locales/ja-JP.json +282 -0
- package/dist/cjs/i18n/locales/ko-KR.json +282 -0
- package/dist/cjs/i18n/locales/locales/ar-SA.json +282 -0
- package/dist/cjs/i18n/locales/locales/ca-ES.json +282 -0
- package/dist/cjs/i18n/locales/locales/de-DE.json +282 -0
- package/dist/cjs/i18n/locales/locales/en-US.json +2161 -0
- package/dist/cjs/i18n/locales/locales/es-ES.json +2161 -0
- package/dist/cjs/i18n/locales/locales/fr-FR.json +282 -0
- package/dist/cjs/i18n/locales/locales/it-IT.json +282 -0
- package/dist/cjs/i18n/locales/locales/ja-JP.json +282 -0
- package/dist/cjs/i18n/locales/locales/ko-KR.json +282 -0
- package/dist/cjs/i18n/locales/locales/pt-PT.json +282 -0
- package/dist/cjs/i18n/locales/locales/zh-CN.json +282 -0
- package/dist/cjs/i18n/locales/pt-PT.json +282 -0
- package/dist/cjs/i18n/locales/zh-CN.json +282 -0
- package/dist/cjs/i18n/reputationCategoryLabels.js +20 -0
- package/dist/cjs/i18n/trustTierLabels.js +19 -0
- package/dist/cjs/index.js +498 -0
- package/dist/cjs/inference/OxyInferenceClient.js +544 -0
- package/dist/cjs/logger/index.js +149 -0
- package/dist/cjs/mixins/OxyServices.accounts.js +555 -0
- package/dist/cjs/mixins/OxyServices.analytics.js +49 -0
- package/dist/cjs/mixins/OxyServices.appData.js +108 -0
- package/dist/cjs/mixins/OxyServices.assets.js +764 -0
- package/dist/cjs/mixins/OxyServices.auth.js +1254 -0
- package/dist/cjs/mixins/OxyServices.chains.js +73 -0
- package/dist/cjs/mixins/OxyServices.civic.js +611 -0
- package/dist/cjs/mixins/OxyServices.connectedApps.js +78 -0
- package/dist/cjs/mixins/OxyServices.contacts.js +50 -0
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +191 -0
- package/dist/cjs/mixins/OxyServices.deviceTransfer.js +314 -0
- package/dist/cjs/mixins/OxyServices.devices.js +116 -0
- package/dist/cjs/mixins/OxyServices.features.js +335 -0
- package/dist/cjs/mixins/OxyServices.followGraph.js +221 -0
- package/dist/cjs/mixins/OxyServices.identity.js +461 -0
- package/dist/cjs/mixins/OxyServices.identityBackup.js +172 -0
- package/dist/cjs/mixins/OxyServices.inference.js +59 -0
- package/dist/cjs/mixins/OxyServices.language.js +125 -0
- package/dist/cjs/mixins/OxyServices.links.js +72 -0
- package/dist/cjs/mixins/OxyServices.location.js +43 -0
- package/dist/cjs/mixins/OxyServices.nodes.js +175 -0
- package/dist/cjs/mixins/OxyServices.notifications.js +63 -0
- package/dist/cjs/mixins/OxyServices.payment.js +158 -0
- package/dist/cjs/mixins/OxyServices.privacy.js +199 -0
- package/dist/cjs/mixins/OxyServices.reputation.js +289 -0
- package/dist/cjs/mixins/OxyServices.security.js +89 -0
- package/dist/cjs/mixins/OxyServices.store.js +266 -0
- package/dist/cjs/mixins/OxyServices.topics.js +137 -0
- package/dist/cjs/mixins/OxyServices.user.js +902 -0
- package/dist/cjs/mixins/OxyServices.utility.js +1098 -0
- package/dist/cjs/mixins/index.js +135 -0
- package/dist/cjs/mixins/mixinHelpers.js +53 -0
- package/dist/cjs/models/Topic.js +16 -0
- package/dist/cjs/models/interfaces.js +20 -0
- package/dist/cjs/models/session.js +2 -0
- package/dist/cjs/server/auth.js +167 -0
- package/dist/cjs/server/capabilityTicket.js +192 -0
- package/dist/cjs/server/cors.js +225 -0
- package/dist/cjs/server/index.js +97 -0
- package/dist/cjs/server/rateLimit.js +207 -0
- package/dist/cjs/server/safeFetch.js +458 -0
- package/dist/cjs/server/securityHeaders.js +377 -0
- package/dist/cjs/server/userInvalidation.js +156 -0
- package/dist/cjs/server/verifySecret.js +50 -0
- package/dist/cjs/session/SessionClient.js +865 -0
- package/dist/cjs/session/accountDelegationAccess.js +48 -0
- package/dist/cjs/session/accountDialogController.js +1131 -0
- package/dist/cjs/session/accountSwitchTargets.js +81 -0
- package/dist/cjs/session/authStateStore.js +404 -0
- package/dist/cjs/session/createSessionClient.js +32 -0
- package/dist/cjs/session/deviceDirectory.js +143 -0
- package/dist/cjs/session/deviceSwitcherRows.js +76 -0
- package/dist/cjs/session/identityPin.js +256 -0
- package/dist/cjs/session/identitySession.js +135 -0
- package/dist/cjs/session/projectSessionState.js +121 -0
- package/dist/cjs/session/refresh.js +398 -0
- package/dist/cjs/session/sessionClientHost.js +34 -0
- package/dist/cjs/session/sharedDeviceCredential.js +247 -0
- package/dist/cjs/session/socketLoader.js +55 -0
- package/dist/cjs/shared/utils/colorUtils.js +153 -0
- package/dist/cjs/shared/utils/errorUtils.js +183 -0
- package/dist/cjs/shared/utils/index.js +49 -0
- package/dist/cjs/shared/utils/networkUtils.js +183 -0
- package/dist/cjs/shared/utils/themeUtils.js +106 -0
- package/dist/cjs/utils/accountCacheSweep.js +80 -0
- package/dist/cjs/utils/accountUtils.js +140 -0
- package/dist/cjs/utils/activityId.js +6 -0
- package/dist/cjs/utils/apiUtils.js +91 -0
- package/dist/cjs/utils/asyncUtils.js +222 -0
- package/dist/cjs/utils/authHelpers.js +120 -0
- package/dist/cjs/utils/authWebUrl.js +19 -0
- package/dist/cjs/utils/avatarUtils.js +29 -0
- package/dist/cjs/utils/cache.js +235 -0
- package/dist/cjs/utils/cacheKey.js +85 -0
- package/dist/cjs/utils/coldBoot.js +122 -0
- package/dist/cjs/utils/commonsApproval.js +31 -0
- package/dist/cjs/utils/commonsDelivery.js +59 -0
- package/dist/cjs/utils/deviceManager.js +174 -0
- package/dist/cjs/utils/displayNamePolicyRanges.generated.js +60 -0
- package/dist/cjs/utils/edgeRegion.js +6 -0
- package/dist/cjs/utils/errorUtils.js +243 -0
- package/dist/cjs/utils/identityCacheSweep.js +97 -0
- package/dist/cjs/utils/languageUtils.js +224 -0
- package/dist/cjs/utils/oauthPkce.js +311 -0
- package/dist/cjs/utils/officialOrigins.js +64 -0
- package/dist/cjs/utils/oxyServiceEnvironment.js +19 -0
- package/dist/cjs/utils/platform.js +119 -0
- package/dist/cjs/utils/profileLinks.js +63 -0
- package/dist/cjs/utils/redactUrl.js +29 -0
- package/dist/cjs/utils/registrableApex.js +45 -0
- package/dist/cjs/utils/requestUtils.js +209 -0
- package/dist/cjs/utils/sessionUtils.js +181 -0
- package/dist/cjs/utils/textNormalization.js +158 -0
- package/dist/cjs/utils/userHandle.js +37 -0
- package/dist/cjs/utils/userIdentity.js +50 -0
- package/dist/cjs/utils/validationUtils.js +370 -0
- package/dist/cjs/utils/webauthnOrigin.js +51 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/dist/esm/HttpService.js +1266 -0
- package/dist/esm/OxyServices.base.js +386 -0
- package/dist/esm/OxyServices.errors.js +88 -0
- package/dist/esm/OxyServices.js +66 -0
- package/dist/esm/boot/sessionColdBoot.js +392 -0
- package/dist/esm/constants/version.js +13 -0
- package/dist/esm/crypto/aead.js +74 -0
- package/dist/esm/crypto/ecdh.js +32 -0
- package/dist/esm/crypto/identityMarker.js +248 -0
- package/dist/esm/crypto/kdf.js +36 -0
- package/dist/esm/crypto/keyManager.js +2227 -0
- package/dist/esm/crypto/polyfill.js +129 -0
- package/dist/esm/crypto/recoveryPhrase.js +238 -0
- package/dist/esm/crypto/signatureService.js +269 -0
- package/dist/esm/i18n/accountCategoryLabels.js +37 -0
- package/dist/esm/i18n/accountRoleLabels.js +20 -0
- package/dist/esm/i18n/index.js +83 -0
- package/dist/esm/i18n/locales/ar-SA.json +282 -0
- package/dist/esm/i18n/locales/ca-ES.json +282 -0
- package/dist/esm/i18n/locales/de-DE.json +282 -0
- package/dist/esm/i18n/locales/en-US.json +2161 -0
- package/dist/esm/i18n/locales/es-ES.json +2161 -0
- package/dist/esm/i18n/locales/fr-FR.json +282 -0
- package/dist/esm/i18n/locales/it-IT.json +282 -0
- package/dist/esm/i18n/locales/ja-JP.json +282 -0
- package/dist/esm/i18n/locales/ko-KR.json +282 -0
- package/dist/esm/i18n/locales/locales/ar-SA.json +282 -0
- package/dist/esm/i18n/locales/locales/ca-ES.json +282 -0
- package/dist/esm/i18n/locales/locales/de-DE.json +282 -0
- package/dist/esm/i18n/locales/locales/en-US.json +2161 -0
- package/dist/esm/i18n/locales/locales/es-ES.json +2161 -0
- package/dist/esm/i18n/locales/locales/fr-FR.json +282 -0
- package/dist/esm/i18n/locales/locales/it-IT.json +282 -0
- package/dist/esm/i18n/locales/locales/ja-JP.json +282 -0
- package/dist/esm/i18n/locales/locales/ko-KR.json +282 -0
- package/dist/esm/i18n/locales/locales/pt-PT.json +282 -0
- package/dist/esm/i18n/locales/locales/zh-CN.json +282 -0
- package/dist/esm/i18n/locales/pt-PT.json +282 -0
- package/dist/esm/i18n/locales/zh-CN.json +282 -0
- package/dist/esm/i18n/reputationCategoryLabels.js +13 -0
- package/dist/esm/i18n/trustTierLabels.js +12 -0
- package/dist/esm/index.js +254 -0
- package/dist/esm/inference/OxyInferenceClient.js +538 -0
- package/dist/esm/logger/index.js +140 -0
- package/dist/esm/mixins/OxyServices.accounts.js +543 -0
- package/dist/esm/mixins/OxyServices.analytics.js +46 -0
- package/dist/esm/mixins/OxyServices.appData.js +103 -0
- package/dist/esm/mixins/OxyServices.assets.js +761 -0
- package/dist/esm/mixins/OxyServices.auth.js +1247 -0
- package/dist/esm/mixins/OxyServices.chains.js +70 -0
- package/dist/esm/mixins/OxyServices.civic.js +605 -0
- package/dist/esm/mixins/OxyServices.connectedApps.js +75 -0
- package/dist/esm/mixins/OxyServices.contacts.js +47 -0
- package/dist/esm/mixins/OxyServices.deviceBoot.js +186 -0
- package/dist/esm/mixins/OxyServices.deviceTransfer.js +311 -0
- package/dist/esm/mixins/OxyServices.devices.js +113 -0
- package/dist/esm/mixins/OxyServices.features.js +332 -0
- package/dist/esm/mixins/OxyServices.followGraph.js +218 -0
- package/dist/esm/mixins/OxyServices.identity.js +457 -0
- package/dist/esm/mixins/OxyServices.identityBackup.js +169 -0
- package/dist/esm/mixins/OxyServices.inference.js +56 -0
- package/dist/esm/mixins/OxyServices.language.js +122 -0
- package/dist/esm/mixins/OxyServices.links.js +69 -0
- package/dist/esm/mixins/OxyServices.location.js +40 -0
- package/dist/esm/mixins/OxyServices.nodes.js +172 -0
- package/dist/esm/mixins/OxyServices.notifications.js +60 -0
- package/dist/esm/mixins/OxyServices.payment.js +155 -0
- package/dist/esm/mixins/OxyServices.privacy.js +196 -0
- package/dist/esm/mixins/OxyServices.reputation.js +286 -0
- package/dist/esm/mixins/OxyServices.security.js +86 -0
- package/dist/esm/mixins/OxyServices.store.js +263 -0
- package/dist/esm/mixins/OxyServices.topics.js +134 -0
- package/dist/esm/mixins/OxyServices.user.js +899 -0
- package/dist/esm/mixins/OxyServices.utility.js +1095 -0
- package/dist/esm/mixins/index.js +132 -0
- package/dist/esm/mixins/mixinHelpers.js +48 -0
- package/dist/esm/models/Topic.js +13 -0
- package/dist/esm/models/interfaces.js +17 -0
- package/dist/esm/models/session.js +1 -0
- package/dist/esm/server/auth.js +154 -0
- package/dist/esm/server/capabilityTicket.js +183 -0
- package/dist/esm/server/cors.js +220 -0
- package/dist/esm/server/index.js +47 -0
- package/dist/esm/server/rateLimit.js +201 -0
- package/dist/esm/server/safeFetch.js +447 -0
- package/dist/esm/server/securityHeaders.js +364 -0
- package/dist/esm/server/userInvalidation.js +152 -0
- package/dist/esm/server/verifySecret.js +47 -0
- package/dist/esm/session/SessionClient.js +861 -0
- package/dist/esm/session/accountDelegationAccess.js +45 -0
- package/dist/esm/session/accountDialogController.js +1126 -0
- package/dist/esm/session/accountSwitchTargets.js +77 -0
- package/dist/esm/session/authStateStore.js +398 -0
- package/dist/esm/session/createSessionClient.js +29 -0
- package/dist/esm/session/deviceDirectory.js +135 -0
- package/dist/esm/session/deviceSwitcherRows.js +72 -0
- package/dist/esm/session/identityPin.js +249 -0
- package/dist/esm/session/identitySession.js +131 -0
- package/dist/esm/session/projectSessionState.js +114 -0
- package/dist/esm/session/refresh.js +390 -0
- package/dist/esm/session/sessionClientHost.js +31 -0
- package/dist/esm/session/sharedDeviceCredential.js +239 -0
- package/dist/esm/session/socketLoader.js +19 -0
- package/dist/esm/shared/utils/colorUtils.js +143 -0
- package/dist/esm/shared/utils/errorUtils.js +170 -0
- package/dist/esm/shared/utils/index.js +15 -0
- package/dist/esm/shared/utils/networkUtils.js +173 -0
- package/dist/esm/shared/utils/themeUtils.js +98 -0
- package/dist/esm/utils/accountCacheSweep.js +75 -0
- package/dist/esm/utils/accountUtils.js +131 -0
- package/dist/esm/utils/activityId.js +2 -0
- package/dist/esm/utils/apiUtils.js +84 -0
- package/dist/esm/utils/asyncUtils.js +207 -0
- package/dist/esm/utils/authHelpers.js +111 -0
- package/dist/esm/utils/authWebUrl.js +16 -0
- package/dist/esm/utils/avatarUtils.js +26 -0
- package/dist/esm/utils/cache.js +227 -0
- package/dist/esm/utils/cacheKey.js +80 -0
- package/dist/esm/utils/coldBoot.js +119 -0
- package/dist/esm/utils/commonsApproval.js +27 -0
- package/dist/esm/utils/commonsDelivery.js +54 -0
- package/dist/esm/utils/deviceManager.js +170 -0
- package/dist/esm/utils/displayNamePolicyRanges.generated.js +57 -0
- package/dist/esm/utils/edgeRegion.js +2 -0
- package/dist/esm/utils/errorUtils.js +232 -0
- package/dist/esm/utils/identityCacheSweep.js +92 -0
- package/dist/esm/utils/languageUtils.js +212 -0
- package/dist/esm/utils/oauthPkce.js +297 -0
- package/dist/esm/utils/officialOrigins.js +59 -0
- package/dist/esm/utils/oxyServiceEnvironment.js +16 -0
- package/dist/esm/utils/platform.js +110 -0
- package/dist/esm/utils/profileLinks.js +60 -0
- package/dist/esm/utils/redactUrl.js +26 -0
- package/dist/esm/utils/registrableApex.js +42 -0
- package/dist/esm/utils/requestUtils.js +203 -0
- package/dist/esm/utils/sessionUtils.js +171 -0
- package/dist/esm/utils/textNormalization.js +154 -0
- package/dist/esm/utils/userHandle.js +33 -0
- package/dist/esm/utils/userIdentity.js +45 -0
- package/dist/esm/utils/validationUtils.js +350 -0
- package/dist/esm/utils/webauthnOrigin.js +48 -0
- package/dist/types/.tsbuildinfo +1 -0
- package/dist/types/HttpService.d.ts +413 -0
- package/dist/types/OxyServices.base.d.ts +187 -0
- package/dist/types/OxyServices.d.ts +139 -0
- package/dist/types/OxyServices.errors.d.ts +84 -0
- package/dist/types/boot/sessionColdBoot.d.ts +140 -0
- package/dist/types/constants/version.d.ts +13 -0
- package/dist/types/crypto/aead.d.ts +56 -0
- package/dist/types/crypto/ecdh.d.ts +29 -0
- package/dist/types/crypto/identityMarker.d.ts +94 -0
- package/dist/types/crypto/kdf.d.ts +25 -0
- package/dist/types/crypto/keyManager.d.ts +582 -0
- package/dist/types/crypto/polyfill.d.ts +25 -0
- package/dist/types/crypto/recoveryPhrase.d.ts +173 -0
- package/dist/types/crypto/signatureService.d.ts +136 -0
- package/dist/types/i18n/accountCategoryLabels.d.ts +34 -0
- package/dist/types/i18n/accountRoleLabels.d.ts +10 -0
- package/dist/types/i18n/index.d.ts +3 -0
- package/dist/types/i18n/reputationCategoryLabels.d.ts +10 -0
- package/dist/types/i18n/trustTierLabels.d.ts +9 -0
- package/dist/types/index.d.ts +145 -0
- package/dist/types/inference/OxyInferenceClient.d.ts +342 -0
- package/dist/types/logger/index.d.ts +104 -0
- package/dist/types/mixins/OxyServices.accounts.d.ts +868 -0
- package/dist/types/mixins/OxyServices.analytics.d.ts +72 -0
- package/dist/types/mixins/OxyServices.appData.d.ts +108 -0
- package/dist/types/mixins/OxyServices.assets.d.ts +329 -0
- package/dist/types/mixins/OxyServices.auth.d.ts +908 -0
- package/dist/types/mixins/OxyServices.chains.d.ts +156 -0
- package/dist/types/mixins/OxyServices.civic.d.ts +510 -0
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +169 -0
- package/dist/types/mixins/OxyServices.contacts.d.ts +100 -0
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +185 -0
- package/dist/types/mixins/OxyServices.deviceTransfer.d.ts +149 -0
- package/dist/types/mixins/OxyServices.devices.d.ts +103 -0
- package/dist/types/mixins/OxyServices.features.d.ts +250 -0
- package/dist/types/mixins/OxyServices.followGraph.d.ts +223 -0
- package/dist/types/mixins/OxyServices.identity.d.ts +351 -0
- package/dist/types/mixins/OxyServices.identityBackup.d.ts +129 -0
- package/dist/types/mixins/OxyServices.inference.d.ts +95 -0
- package/dist/types/mixins/OxyServices.language.d.ts +87 -0
- package/dist/types/mixins/OxyServices.links.d.ts +104 -0
- package/dist/types/mixins/OxyServices.location.d.ts +70 -0
- package/dist/types/mixins/OxyServices.nodes.d.ts +198 -0
- package/dist/types/mixins/OxyServices.notifications.d.ts +143 -0
- package/dist/types/mixins/OxyServices.payment.d.ts +117 -0
- package/dist/types/mixins/OxyServices.privacy.d.ts +146 -0
- package/dist/types/mixins/OxyServices.reputation.d.ts +202 -0
- package/dist/types/mixins/OxyServices.security.d.ts +84 -0
- package/dist/types/mixins/OxyServices.store.d.ts +334 -0
- package/dist/types/mixins/OxyServices.topics.d.ts +110 -0
- package/dist/types/mixins/OxyServices.user.d.ts +558 -0
- package/dist/types/mixins/OxyServices.utility.d.ts +393 -0
- package/dist/types/mixins/index.d.ts +87 -0
- package/dist/types/mixins/mixinHelpers.d.ts +31 -0
- package/dist/types/models/Topic.d.ts +42 -0
- package/dist/types/models/interfaces.d.ts +675 -0
- package/dist/types/models/session.d.ts +51 -0
- package/dist/types/server/auth.d.ts +130 -0
- package/dist/types/server/capabilityTicket.d.ts +41 -0
- package/dist/types/server/cors.d.ts +98 -0
- package/dist/types/server/index.d.ts +35 -0
- package/dist/types/server/rateLimit.d.ts +40 -0
- package/dist/types/server/safeFetch.d.ts +137 -0
- package/dist/types/server/securityHeaders.d.ts +221 -0
- package/dist/types/server/userInvalidation.d.ts +114 -0
- package/dist/types/server/verifySecret.d.ts +29 -0
- package/dist/types/session/SessionClient.d.ts +418 -0
- package/dist/types/session/accountDelegationAccess.d.ts +40 -0
- package/dist/types/session/accountDialogController.d.ts +648 -0
- package/dist/types/session/accountSwitchTargets.d.ts +70 -0
- package/dist/types/session/authStateStore.d.ts +153 -0
- package/dist/types/session/createSessionClient.d.ts +30 -0
- package/dist/types/session/deviceDirectory.d.ts +182 -0
- package/dist/types/session/deviceSwitcherRows.d.ts +92 -0
- package/dist/types/session/identityPin.d.ts +87 -0
- package/dist/types/session/identitySession.d.ts +105 -0
- package/dist/types/session/projectSessionState.d.ts +74 -0
- package/dist/types/session/refresh.d.ts +179 -0
- package/dist/types/session/sessionClientHost.d.ts +18 -0
- package/dist/types/session/sharedDeviceCredential.d.ts +202 -0
- package/dist/types/session/socketLoader.d.ts +11 -0
- package/dist/types/shared/utils/colorUtils.d.ts +104 -0
- package/dist/types/shared/utils/errorUtils.d.ts +97 -0
- package/dist/types/shared/utils/index.d.ts +13 -0
- package/dist/types/shared/utils/networkUtils.d.ts +139 -0
- package/dist/types/shared/utils/themeUtils.d.ts +90 -0
- package/dist/types/utils/accountCacheSweep.d.ts +75 -0
- package/dist/types/utils/accountUtils.d.ts +100 -0
- package/dist/types/utils/activityId.d.ts +2 -0
- package/dist/types/utils/apiUtils.d.ts +95 -0
- package/dist/types/utils/asyncUtils.d.ts +62 -0
- package/dist/types/utils/authHelpers.d.ts +58 -0
- package/dist/types/utils/authWebUrl.d.ts +16 -0
- package/dist/types/utils/avatarUtils.d.ts +16 -0
- package/dist/types/utils/cache.d.ts +130 -0
- package/dist/types/utils/cacheKey.d.ts +66 -0
- package/dist/types/utils/coldBoot.d.ts +131 -0
- package/dist/types/utils/commonsApproval.d.ts +13 -0
- package/dist/types/utils/commonsDelivery.d.ts +105 -0
- package/dist/types/utils/deviceManager.d.ts +65 -0
- package/dist/types/utils/displayNamePolicyRanges.generated.d.ts +57 -0
- package/dist/types/utils/edgeRegion.d.ts +2 -0
- package/dist/types/utils/errorUtils.d.ts +125 -0
- package/dist/types/utils/identityCacheSweep.d.ts +80 -0
- package/dist/types/utils/languageUtils.d.ts +100 -0
- package/dist/types/utils/oauthPkce.d.ts +157 -0
- package/dist/types/utils/officialOrigins.d.ts +13 -0
- package/dist/types/utils/oxyServiceEnvironment.d.ts +17 -0
- package/dist/types/utils/platform.d.ts +49 -0
- package/dist/types/utils/profileLinks.d.ts +44 -0
- package/dist/types/utils/redactUrl.d.ts +17 -0
- package/dist/types/utils/registrableApex.d.ts +27 -0
- package/dist/types/utils/requestUtils.d.ts +123 -0
- package/dist/types/utils/sessionUtils.d.ts +54 -0
- package/dist/types/utils/textNormalization.d.ts +103 -0
- package/dist/types/utils/userHandle.d.ts +26 -0
- package/dist/types/utils/userIdentity.d.ts +21 -0
- package/dist/types/utils/validationUtils.d.ts +268 -0
- package/dist/types/utils/webauthnOrigin.d.ts +32 -0
- package/package.json +168 -0
- package/src/HttpService.ts +1553 -0
- package/src/OxyServices.base.ts +478 -0
- package/src/OxyServices.errors.ts +122 -0
- package/src/OxyServices.ts +172 -0
- package/src/__tests__/authSocket.test.ts +96 -0
- package/src/__tests__/httpServiceActivityId.test.ts +49 -0
- package/src/__tests__/httpServiceAuthSelfAwait.test.ts +108 -0
- package/src/__tests__/httpServiceCache.test.ts +318 -0
- package/src/__tests__/httpServiceCsrf.test.ts +235 -0
- package/src/__tests__/httpServiceFormEncoded.test.ts +142 -0
- package/src/__tests__/httpServiceQueueDeadlock.test.ts +128 -0
- package/src/__tests__/httpServiceUnwrapEnvelope.test.ts +115 -0
- package/src/__tests__/inSessionRefresh.test.ts +260 -0
- package/src/__tests__/linkedClient.test.ts +370 -0
- package/src/__tests__/parseHttpErrorBody.test.ts +116 -0
- package/src/__tests__/serverValueImportsDeclared.test.ts +120 -0
- package/src/__tests__/userIdentity.test.ts +143 -0
- package/src/boot/__tests__/sessionColdBoot.identity.test.ts +393 -0
- package/src/boot/__tests__/sessionColdBoot.sharedDevice.test.ts +325 -0
- package/src/boot/__tests__/sessionColdBoot.test.ts +570 -0
- package/src/boot/sessionColdBoot.ts +529 -0
- package/src/constants/version.ts +15 -0
- package/src/crypto/__tests__/backupMaterial.test.ts +86 -0
- package/src/crypto/__tests__/cryptoPrimitives.test.ts +226 -0
- package/src/crypto/__tests__/identityMocks.ts +125 -0
- package/src/crypto/__tests__/keyManager.atomicity.test.ts +272 -0
- package/src/crypto/__tests__/keyManager.cacheSafety.test.ts +175 -0
- package/src/crypto/__tests__/keyManager.identityStatus.test.ts +217 -0
- package/src/crypto/__tests__/keyManager.recoveryLadder.test.ts +179 -0
- package/src/crypto/__tests__/keyManager.recoveryMnemonic.test.ts +138 -0
- package/src/crypto/__tests__/keyManager.storageMigration.test.ts +227 -0
- package/src/crypto/__tests__/keyManager.test.ts +329 -0
- package/src/crypto/__tests__/polyfill.test.ts +109 -0
- package/src/crypto/__tests__/recoveryPhrase.test.ts +61 -0
- package/src/crypto/__tests__/scopedSeed.test.ts +126 -0
- package/src/crypto/__tests__/signChallengeShared.test.ts +63 -0
- package/src/crypto/__tests__/signedRecord.test.ts +230 -0
- package/src/crypto/aead.ts +97 -0
- package/src/crypto/ecdh.ts +37 -0
- package/src/crypto/identityMarker.ts +291 -0
- package/src/crypto/kdf.ts +43 -0
- package/src/crypto/keyManager.ts +2607 -0
- package/src/crypto/polyfill.ts +143 -0
- package/src/crypto/recoveryPhrase.ts +337 -0
- package/src/crypto/signatureService.ts +350 -0
- package/src/i18n/__tests__/accountCategoryLabels.test.ts +62 -0
- package/src/i18n/__tests__/accountRoleLabels.test.ts +54 -0
- package/src/i18n/__tests__/reputationCategoryLabels.test.ts +56 -0
- package/src/i18n/__tests__/trustTierLabels.test.ts +47 -0
- package/src/i18n/accountCategoryLabels.ts +44 -0
- package/src/i18n/accountRoleLabels.ts +26 -0
- package/src/i18n/index.ts +88 -0
- package/src/i18n/locales/ar-SA.json +282 -0
- package/src/i18n/locales/ca-ES.json +282 -0
- package/src/i18n/locales/de-DE.json +282 -0
- package/src/i18n/locales/en-US.json +2161 -0
- package/src/i18n/locales/es-ES.json +2161 -0
- package/src/i18n/locales/fr-FR.json +282 -0
- package/src/i18n/locales/it-IT.json +282 -0
- package/src/i18n/locales/ja-JP.json +282 -0
- package/src/i18n/locales/ko-KR.json +282 -0
- package/src/i18n/locales/pt-PT.json +282 -0
- package/src/i18n/locales/zh-CN.json +282 -0
- package/src/i18n/reputationCategoryLabels.ts +20 -0
- package/src/i18n/trustTierLabels.ts +18 -0
- package/src/index.ts +881 -0
- package/src/inference/OxyInferenceClient.ts +888 -0
- package/src/inference/__tests__/OxyInferenceClient.test.ts +834 -0
- package/src/logger/__tests__/logger.test.ts +207 -0
- package/src/logger/index.ts +217 -0
- package/src/mixins/OxyServices.accounts.ts +1330 -0
- package/src/mixins/OxyServices.analytics.ts +53 -0
- package/src/mixins/OxyServices.appData.ts +158 -0
- package/src/mixins/OxyServices.assets.ts +861 -0
- package/src/mixins/OxyServices.auth.ts +1858 -0
- package/src/mixins/OxyServices.chains.ts +134 -0
- package/src/mixins/OxyServices.civic.ts +945 -0
- package/src/mixins/OxyServices.connectedApps.ts +174 -0
- package/src/mixins/OxyServices.contacts.ts +73 -0
- package/src/mixins/OxyServices.deviceBoot.ts +210 -0
- package/src/mixins/OxyServices.deviceTransfer.ts +393 -0
- package/src/mixins/OxyServices.devices.ts +120 -0
- package/src/mixins/OxyServices.features.ts +454 -0
- package/src/mixins/OxyServices.followGraph.ts +293 -0
- package/src/mixins/OxyServices.identity.ts +705 -0
- package/src/mixins/OxyServices.identityBackup.ts +250 -0
- package/src/mixins/OxyServices.inference.ts +57 -0
- package/src/mixins/OxyServices.language.ts +144 -0
- package/src/mixins/OxyServices.links.ts +107 -0
- package/src/mixins/OxyServices.location.ts +46 -0
- package/src/mixins/OxyServices.nodes.ts +337 -0
- package/src/mixins/OxyServices.notifications.ts +142 -0
- package/src/mixins/OxyServices.payment.ts +163 -0
- package/src/mixins/OxyServices.privacy.ts +219 -0
- package/src/mixins/OxyServices.reputation.ts +436 -0
- package/src/mixins/OxyServices.security.ts +110 -0
- package/src/mixins/OxyServices.store.ts +585 -0
- package/src/mixins/OxyServices.topics.ts +169 -0
- package/src/mixins/OxyServices.user.ts +1137 -0
- package/src/mixins/OxyServices.utility.ts +1370 -0
- package/src/mixins/__tests__/OxyServices.civic.test.ts +1095 -0
- package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +124 -0
- package/src/mixins/__tests__/OxyServices.deviceTransfer.test.ts +271 -0
- package/src/mixins/__tests__/OxyServices.identity.test.ts +376 -0
- package/src/mixins/__tests__/OxyServices.links.test.ts +154 -0
- package/src/mixins/__tests__/OxyServices.nodes.test.ts +341 -0
- package/src/mixins/__tests__/OxyServices.rotateKey.test.ts +276 -0
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadata.test.ts +192 -0
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadataBySha.test.ts +135 -0
- package/src/mixins/__tests__/accounts.test.ts +727 -0
- package/src/mixins/__tests__/appData.test.ts +203 -0
- package/src/mixins/__tests__/assetCredentials.test.ts +47 -0
- package/src/mixins/__tests__/assetUpload.test.ts +191 -0
- package/src/mixins/__tests__/backgroundCredential.httpIntegration.test.ts +135 -0
- package/src/mixins/__tests__/chains.test.ts +113 -0
- package/src/mixins/__tests__/commonsSignIn.test.ts +1144 -0
- package/src/mixins/__tests__/connectedApps.test.ts +123 -0
- package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +113 -0
- package/src/mixins/__tests__/discoveryErrorHandling.test.ts +266 -0
- package/src/mixins/__tests__/followCacheInvalidation.test.ts +173 -0
- package/src/mixins/__tests__/followGraph.test.ts +147 -0
- package/src/mixins/__tests__/followGraphPagination.test.ts +271 -0
- package/src/mixins/__tests__/getFileDownloadUrl.test.ts +346 -0
- package/src/mixins/__tests__/getFollowStatuses.test.ts +95 -0
- package/src/mixins/__tests__/getUsersByIds.test.ts +149 -0
- package/src/mixins/__tests__/identityBackup.test.ts +315 -0
- package/src/mixins/__tests__/identityWriteCacheInvalidation.test.ts +407 -0
- package/src/mixins/__tests__/inferenceFactory.test.ts +58 -0
- package/src/mixins/__tests__/onTokensChanged.test.ts +129 -0
- package/src/mixins/__tests__/preSessionSkipAuth.test.ts +284 -0
- package/src/mixins/__tests__/privacyCacheInvalidation.test.ts +155 -0
- package/src/mixins/__tests__/reputation.test.ts +522 -0
- package/src/mixins/__tests__/serviceAuth.test.ts +832 -0
- package/src/mixins/__tests__/serviceTokenJwks.test.ts +208 -0
- package/src/mixins/__tests__/store.test.ts +304 -0
- package/src/mixins/__tests__/topics.test.ts +156 -0
- package/src/mixins/__tests__/userReadCacheBypass.test.ts +129 -0
- package/src/mixins/__tests__/userTokenAuth.test.ts +746 -0
- package/src/mixins/__tests__/verifyChallenge.test.ts +130 -0
- package/src/mixins/__tests__/verifyServiceActingAs.test.ts +167 -0
- package/src/mixins/__tests__/webauthnAuth.test.ts +205 -0
- package/src/mixins/index.ts +201 -0
- package/src/mixins/mixinHelpers.ts +69 -0
- package/src/models/Topic.ts +46 -0
- package/src/models/interfaces.ts +786 -0
- package/src/models/session.ts +55 -0
- package/src/server/__tests__/auth.test.ts +78 -0
- package/src/server/__tests__/capabilityTicket.test.ts +111 -0
- package/src/server/__tests__/cors.socket.test.ts +225 -0
- package/src/server/__tests__/cors.test.ts +158 -0
- package/src/server/__tests__/rateLimit.test.ts +257 -0
- package/src/server/__tests__/safeFetch.test.ts +232 -0
- package/src/server/__tests__/securityHeaders.test.ts +348 -0
- package/src/server/__tests__/serviceTokenAttribution.test.ts +396 -0
- package/src/server/__tests__/userInvalidation.test.ts +203 -0
- package/src/server/__tests__/verifySecret.test.ts +40 -0
- package/src/server/auth.ts +271 -0
- package/src/server/capabilityTicket.ts +258 -0
- package/src/server/cors.ts +277 -0
- package/src/server/index.ts +136 -0
- package/src/server/rateLimit.ts +313 -0
- package/src/server/safeFetch.ts +586 -0
- package/src/server/securityHeaders.ts +467 -0
- package/src/server/userInvalidation.ts +199 -0
- package/src/server/verifySecret.ts +52 -0
- package/src/session/SessionClient.ts +1001 -0
- package/src/session/__tests__/SessionClient.additive.test.ts +153 -0
- package/src/session/__tests__/SessionClient.broadcastChannel.test.ts +114 -0
- package/src/session/__tests__/SessionClient.diagnostics.test.ts +91 -0
- package/src/session/__tests__/SessionClient.directory.test.ts +688 -0
- package/src/session/__tests__/SessionClient.httpIntegration.test.ts +65 -0
- package/src/session/__tests__/SessionClient.identityPin.test.ts +175 -0
- package/src/session/__tests__/SessionClient.rest.test.ts +119 -0
- package/src/session/__tests__/SessionClient.serverEvents.test.ts +72 -0
- package/src/session/__tests__/SessionClient.socket.test.ts +202 -0
- package/src/session/__tests__/SessionClient.socketFactory.test.ts +81 -0
- package/src/session/__tests__/SessionClient.state.test.ts +78 -0
- package/src/session/__tests__/SessionClient.switchTokenOrder.test.ts +170 -0
- package/src/session/__tests__/accountDelegationAccess.test.ts +104 -0
- package/src/session/__tests__/accountDialogController.test.ts +1969 -0
- package/src/session/__tests__/accountDialogShape.test.ts +118 -0
- package/src/session/__tests__/accountSwitchTargets.test.ts +137 -0
- package/src/session/__tests__/authStateStore.test.ts +451 -0
- package/src/session/__tests__/deviceDirectory.test.ts +422 -0
- package/src/session/__tests__/deviceSwitcherRows.test.ts +223 -0
- package/src/session/__tests__/identityPin.test.ts +131 -0
- package/src/session/__tests__/identitySession.test.ts +194 -0
- package/src/session/__tests__/projectSessionState.test.ts +105 -0
- package/src/session/__tests__/refresh.identityPin.test.ts +307 -0
- package/src/session/__tests__/refresh.test.ts +443 -0
- package/src/session/__tests__/sessionIntegration.test.ts +209 -0
- package/src/session/__tests__/sharedDeviceCredential.test.ts +300 -0
- package/src/session/accountDelegationAccess.ts +72 -0
- package/src/session/accountDialogController.ts +1494 -0
- package/src/session/accountSwitchTargets.ts +93 -0
- package/src/session/authStateStore.ts +502 -0
- package/src/session/createSessionClient.ts +39 -0
- package/src/session/deviceDirectory.ts +269 -0
- package/src/session/deviceSwitcherRows.ts +145 -0
- package/src/session/identityPin.ts +310 -0
- package/src/session/identitySession.ts +206 -0
- package/src/session/projectSessionState.ts +137 -0
- package/src/session/refresh.ts +517 -0
- package/src/session/sessionClientHost.ts +39 -0
- package/src/session/sharedDeviceCredential.ts +349 -0
- package/src/session/socketLoader.ts +30 -0
- package/src/shared/utils/colorUtils.ts +155 -0
- package/src/shared/utils/errorUtils.ts +181 -0
- package/src/shared/utils/index.ts +59 -0
- package/src/shared/utils/networkUtils.ts +248 -0
- package/src/shared/utils/themeUtils.ts +115 -0
- package/src/types/buffer.d.ts +97 -0
- package/src/types/expo-crypto.d.ts +16 -0
- package/src/types/expo-secure-store.d.ts +17 -0
- package/src/utils/__tests__/accountUtils.test.ts +151 -0
- package/src/utils/__tests__/activityId.test.ts +45 -0
- package/src/utils/__tests__/asyncUtils.test.ts +187 -0
- package/src/utils/__tests__/authWebUrl.test.ts +15 -0
- package/src/utils/__tests__/cacheKey.test.ts +0 -0
- package/src/utils/__tests__/coldBoot.test.ts +496 -0
- package/src/utils/__tests__/commonsApproval.test.ts +60 -0
- package/src/utils/__tests__/identityCacheSweep.test.ts +151 -0
- package/src/utils/__tests__/languageUtils.test.ts +219 -0
- package/src/utils/__tests__/oauthPkce.test.ts +272 -0
- package/src/utils/__tests__/officialOrigins.test.ts +31 -0
- package/src/utils/__tests__/oxyServiceEnvironment.test.ts +7 -0
- package/src/utils/__tests__/profileLinks.test.ts +180 -0
- package/src/utils/__tests__/redactUrl.test.ts +33 -0
- package/src/utils/__tests__/registrableApex.test.ts +62 -0
- package/src/utils/__tests__/textNormalization.test.ts +205 -0
- package/src/utils/__tests__/validationUtils.test.ts +703 -0
- package/src/utils/__tests__/webauthnOrigin.test.ts +83 -0
- package/src/utils/accountCacheSweep.ts +93 -0
- package/src/utils/accountUtils.ts +194 -0
- package/src/utils/activityId.ts +2 -0
- package/src/utils/apiUtils.ts +137 -0
- package/src/utils/asyncUtils.ts +280 -0
- package/src/utils/authHelpers.ts +148 -0
- package/src/utils/authWebUrl.ts +17 -0
- package/src/utils/avatarUtils.ts +39 -0
- package/src/utils/cache.ts +273 -0
- package/src/utils/cacheKey.ts +93 -0
- package/src/utils/coldBoot.ts +218 -0
- package/src/utils/commonsApproval.ts +39 -0
- package/src/utils/commonsDelivery.ts +132 -0
- package/src/utils/deviceManager.ts +203 -0
- package/src/utils/displayNamePolicyRanges.generated.ts +69 -0
- package/src/utils/edgeRegion.ts +2 -0
- package/src/utils/errorUtils.ts +352 -0
- package/src/utils/identityCacheSweep.ts +104 -0
- package/src/utils/languageUtils.ts +256 -0
- package/src/utils/oauthPkce.ts +392 -0
- package/src/utils/officialOrigins.ts +62 -0
- package/src/utils/oxyServiceEnvironment.ts +17 -0
- package/src/utils/platform.ts +139 -0
- package/src/utils/profileLinks.ts +91 -0
- package/src/utils/redactUrl.ts +28 -0
- package/src/utils/registrableApex.ts +41 -0
- package/src/utils/requestUtils.ts +237 -0
- package/src/utils/sessionUtils.ts +206 -0
- package/src/utils/textNormalization.ts +162 -0
- package/src/utils/userHandle.ts +49 -0
- package/src/utils/userIdentity.ts +60 -0
- package/src/utils/validationUtils.ts +390 -0
- package/src/utils/webauthnOrigin.ts +52 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signature Service - ECDSA Digital Signatures (device-key bound)
|
|
3
|
+
*
|
|
4
|
+
* Handles signing and verification of messages with the user's DEVICE identity
|
|
5
|
+
* key (read from {@link KeyManager} / secure storage). All cryptography itself —
|
|
6
|
+
* canonical signing input, SHA-256, secp256k1 sign/verify, envelope assembly —
|
|
7
|
+
* is delegated to `@oxy.so/protocol`; this service only resolves the key from
|
|
8
|
+
* storage and orchestrates the protocol primitives.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { SignedRecordEnvelope } from '@oxy.so/contracts';
|
|
12
|
+
import {
|
|
13
|
+
signEnvelope,
|
|
14
|
+
signMessage,
|
|
15
|
+
verifySignature,
|
|
16
|
+
sha256,
|
|
17
|
+
loadExpoCrypto,
|
|
18
|
+
loadNodeCrypto,
|
|
19
|
+
isReactNative,
|
|
20
|
+
isNodeJS,
|
|
21
|
+
} from '@oxy.so/protocol';
|
|
22
|
+
import { KeyManager } from './keyManager';
|
|
23
|
+
import { logger } from '../logger';
|
|
24
|
+
|
|
25
|
+
export interface SignedMessage {
|
|
26
|
+
message: string;
|
|
27
|
+
signature: string;
|
|
28
|
+
publicKey: string;
|
|
29
|
+
timestamp: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AuthChallenge {
|
|
33
|
+
challenge: string;
|
|
34
|
+
publicKey: string;
|
|
35
|
+
timestamp: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class SignatureService {
|
|
39
|
+
/**
|
|
40
|
+
* Generate a random challenge string (for offline use)
|
|
41
|
+
* Uses expo-crypto in React Native, crypto.randomBytes in Node.js
|
|
42
|
+
*/
|
|
43
|
+
static async generateChallenge(): Promise<string> {
|
|
44
|
+
// In React Native, use expo-crypto
|
|
45
|
+
if (isReactNative()) {
|
|
46
|
+
const Crypto = await loadExpoCrypto();
|
|
47
|
+
const randomBytes = await Crypto.getRandomBytesAsync(32);
|
|
48
|
+
return Array.from(new Uint8Array(randomBytes))
|
|
49
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
50
|
+
.join('');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (isNodeJS()) {
|
|
54
|
+
try {
|
|
55
|
+
const nodeCrypto = await loadNodeCrypto();
|
|
56
|
+
return nodeCrypto.randomBytes(32).toString('hex');
|
|
57
|
+
} catch (error) {
|
|
58
|
+
// Node crypto failed to load — log and fall through to Web Crypto API
|
|
59
|
+
logger.warn('[oxy.crypto] Node crypto unavailable, falling back to Web Crypto', { component: 'SignatureService' }, error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Browser: use Web Crypto API
|
|
64
|
+
const bytes = new Uint8Array(32);
|
|
65
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
66
|
+
return Array.from(bytes)
|
|
67
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
68
|
+
.join('');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Hash a message using SHA-256
|
|
73
|
+
*/
|
|
74
|
+
static async hashMessage(message: string): Promise<string> {
|
|
75
|
+
return sha256(message);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Sign a message using the stored device private key
|
|
80
|
+
* Returns the signature in DER format (hex encoded)
|
|
81
|
+
*/
|
|
82
|
+
static async sign(message: string): Promise<string> {
|
|
83
|
+
const privateKey = await KeyManager.getPrivateKey();
|
|
84
|
+
if (!privateKey) {
|
|
85
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
86
|
+
}
|
|
87
|
+
return signMessage(message, privateKey);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create a signed message object with metadata
|
|
92
|
+
*/
|
|
93
|
+
static async createSignedMessage(message: string): Promise<SignedMessage> {
|
|
94
|
+
const publicKey = await KeyManager.getPublicKey();
|
|
95
|
+
if (!publicKey) {
|
|
96
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const timestamp = Date.now();
|
|
100
|
+
const messageWithTimestamp = `${message}:${timestamp}`;
|
|
101
|
+
const signature = await SignatureService.sign(messageWithTimestamp);
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
message,
|
|
105
|
+
signature,
|
|
106
|
+
publicKey,
|
|
107
|
+
timestamp,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Verify a signed message object
|
|
113
|
+
* Checks both signature validity and timestamp freshness
|
|
114
|
+
*/
|
|
115
|
+
static async verifySignedMessage(
|
|
116
|
+
signedMessage: SignedMessage,
|
|
117
|
+
maxAgeMs: number = 5 * 60 * 1000 // 5 minutes default
|
|
118
|
+
): Promise<boolean> {
|
|
119
|
+
const { message, signature, publicKey, timestamp } = signedMessage;
|
|
120
|
+
|
|
121
|
+
// Check timestamp freshness
|
|
122
|
+
const now = Date.now();
|
|
123
|
+
if (now - timestamp > maxAgeMs) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Verify signature
|
|
128
|
+
const messageWithTimestamp = `${message}:${timestamp}`;
|
|
129
|
+
return verifySignature(messageWithTimestamp, signature, publicKey);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Create a signed authentication challenge response
|
|
134
|
+
* Used for challenge-response authentication
|
|
135
|
+
*/
|
|
136
|
+
static async signChallenge(challenge: string): Promise<AuthChallenge> {
|
|
137
|
+
const publicKey = await KeyManager.getPublicKey();
|
|
138
|
+
if (!publicKey) {
|
|
139
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const timestamp = Date.now();
|
|
143
|
+
const message = `auth:${publicKey}:${challenge}:${timestamp}`;
|
|
144
|
+
const signature = await SignatureService.sign(message);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
challenge: signature,
|
|
148
|
+
publicKey,
|
|
149
|
+
timestamp,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Create a signed authentication challenge response using the SHARED identity
|
|
155
|
+
* key (the cross-app `group.so.oxy.shared` keychain key), not the primary
|
|
156
|
+
* device key.
|
|
157
|
+
*
|
|
158
|
+
* Mirrors {@link signChallenge} exactly — same message format
|
|
159
|
+
* (`auth:${publicKey}:${challenge}:${timestamp}`) so the server verification
|
|
160
|
+
* path is unchanged — but sources the shared public/private key from
|
|
161
|
+
* `KeyManager` and signs with the protocol's explicit-key {@link signMessage}.
|
|
162
|
+
* Used by "Sign in with Oxy" same-device shared-keychain SSO (Mechanism A): a
|
|
163
|
+
* sibling native app proves control of the shared identity to mint its own
|
|
164
|
+
* session.
|
|
165
|
+
*
|
|
166
|
+
* Throws if no shared identity exists (native-only; the shared keychain is
|
|
167
|
+
* unavailable on web).
|
|
168
|
+
*/
|
|
169
|
+
static async signChallengeWithSharedKey(challenge: string): Promise<AuthChallenge> {
|
|
170
|
+
const publicKey = await KeyManager.getSharedPublicKey();
|
|
171
|
+
const privateKey = await KeyManager.getSharedPrivateKey();
|
|
172
|
+
if (!publicKey || !privateKey) {
|
|
173
|
+
throw new Error('No shared identity found. Cannot sign with the shared key.');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const timestamp = Date.now();
|
|
177
|
+
const message = `auth:${publicKey}:${challenge}:${timestamp}`;
|
|
178
|
+
const signature = await signMessage(message, privateKey);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
challenge: signature,
|
|
182
|
+
publicKey,
|
|
183
|
+
timestamp,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Verify a challenge response
|
|
189
|
+
*/
|
|
190
|
+
static async verifyChallengeResponse(
|
|
191
|
+
originalChallenge: string,
|
|
192
|
+
response: AuthChallenge,
|
|
193
|
+
maxAgeMs: number = 5 * 60 * 1000
|
|
194
|
+
): Promise<boolean> {
|
|
195
|
+
const { challenge: signature, publicKey, timestamp } = response;
|
|
196
|
+
|
|
197
|
+
// Check timestamp freshness
|
|
198
|
+
const now = Date.now();
|
|
199
|
+
if (now - timestamp > maxAgeMs) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const message = `auth:${publicKey}:${originalChallenge}:${timestamp}`;
|
|
204
|
+
return verifySignature(message, signature, publicKey);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Create a registration signature
|
|
209
|
+
* Used when registering a new identity with the server
|
|
210
|
+
* Format matches server expectation: oxy:register:{publicKey}:{timestamp}
|
|
211
|
+
*/
|
|
212
|
+
static async createRegistrationSignature(): Promise<{ signature: string; publicKey: string; timestamp: number }> {
|
|
213
|
+
const publicKey = await KeyManager.getPublicKey();
|
|
214
|
+
if (!publicKey) {
|
|
215
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const timestamp = Date.now();
|
|
219
|
+
const message = `oxy:register:${publicKey}:${timestamp}`;
|
|
220
|
+
const signature = await SignatureService.sign(message);
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
signature,
|
|
224
|
+
publicKey,
|
|
225
|
+
timestamp,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Sign arbitrary data for API requests
|
|
231
|
+
* Creates a canonical string representation and signs it
|
|
232
|
+
*/
|
|
233
|
+
static async signRequestData(data: Record<string, unknown>): Promise<{
|
|
234
|
+
signature: string;
|
|
235
|
+
publicKey: string;
|
|
236
|
+
timestamp: number;
|
|
237
|
+
}> {
|
|
238
|
+
const publicKey = await KeyManager.getPublicKey();
|
|
239
|
+
if (!publicKey) {
|
|
240
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const timestamp = Date.now();
|
|
244
|
+
|
|
245
|
+
// Create canonical string representation
|
|
246
|
+
const sortedKeys = Object.keys(data).sort();
|
|
247
|
+
const canonicalParts = sortedKeys.map(key => `${key}:${JSON.stringify(data[key])}`);
|
|
248
|
+
const canonicalString = canonicalParts.join('|');
|
|
249
|
+
|
|
250
|
+
const message = `request:${publicKey}:${timestamp}:${canonicalString}`;
|
|
251
|
+
const signature = await SignatureService.sign(message);
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
signature,
|
|
255
|
+
publicKey,
|
|
256
|
+
timestamp,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Build a signed-record envelope for a self-issued identity/profile record.
|
|
262
|
+
*
|
|
263
|
+
* The envelope is self-issued: `issuer` equals `subject` (the signer's DID).
|
|
264
|
+
* The signature covers the canonical JSON of every field EXCEPT `publicKey`
|
|
265
|
+
* and `signature`; `alg` is `ES256K-DER-SHA256` (secp256k1 over the SHA-256 of
|
|
266
|
+
* the canonical bytes, DER-encoded). The cryptography is delegated to the
|
|
267
|
+
* protocol's {@link signEnvelope}, which derives the (uncompressed-hex)
|
|
268
|
+
* `publicKey` from the stored device key — identical to the registered
|
|
269
|
+
* verification method.
|
|
270
|
+
*
|
|
271
|
+
* Requires a stored identity (native secure storage); throws if none exists.
|
|
272
|
+
*
|
|
273
|
+
* @param type - The record category (`'identity'` or `'profile'`).
|
|
274
|
+
* @param subject - The subject DID the record is about (also the issuer).
|
|
275
|
+
* @param record - The arbitrary record payload to attest to.
|
|
276
|
+
*/
|
|
277
|
+
static async signRecord(
|
|
278
|
+
type: SignedRecordEnvelope['type'],
|
|
279
|
+
subject: string,
|
|
280
|
+
record: Record<string, unknown>,
|
|
281
|
+
): Promise<SignedRecordEnvelope> {
|
|
282
|
+
const privateKey = await KeyManager.getPrivateKey();
|
|
283
|
+
if (!privateKey) {
|
|
284
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return signEnvelope(
|
|
288
|
+
{
|
|
289
|
+
version: 1,
|
|
290
|
+
type,
|
|
291
|
+
subject,
|
|
292
|
+
issuer: subject,
|
|
293
|
+
record,
|
|
294
|
+
issuedAt: Date.now(),
|
|
295
|
+
},
|
|
296
|
+
privateKey,
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Build a signed-record envelope (v2) carrying the per-subject hash-chain
|
|
302
|
+
* fields.
|
|
303
|
+
*
|
|
304
|
+
* Identical to {@link signRecord} (self-issued: `issuer === subject`; same
|
|
305
|
+
* `ES256K-DER-SHA256` scheme) but `version` is `2` and the signed bytes
|
|
306
|
+
* additionally cover the chain fields:
|
|
307
|
+
*
|
|
308
|
+
* @param type - The record category.
|
|
309
|
+
* @param subject - The subject DID the record is about (also the issuer).
|
|
310
|
+
* @param record - The arbitrary record payload to attest to.
|
|
311
|
+
* @param chain - The hash-chain coordinates:
|
|
312
|
+
* - `seq` — strictly-increasing sequence number for this subject's chain.
|
|
313
|
+
* - `prev` — the `recordId` of the previous record, or `null` at genesis.
|
|
314
|
+
* - `collection` + `rkey` — the AtProto-style record key.
|
|
315
|
+
*
|
|
316
|
+
* The caller is responsible for fetching the current chain head (so `seq` /
|
|
317
|
+
* `prev` are correct) before signing. Requires a stored identity; throws if
|
|
318
|
+
* none exists.
|
|
319
|
+
*/
|
|
320
|
+
static async signRecordV2(
|
|
321
|
+
type: SignedRecordEnvelope['type'],
|
|
322
|
+
subject: string,
|
|
323
|
+
record: Record<string, unknown>,
|
|
324
|
+
chain: { seq: number; prev: string | null; collection: string; rkey: string },
|
|
325
|
+
): Promise<SignedRecordEnvelope> {
|
|
326
|
+
const privateKey = await KeyManager.getPrivateKey();
|
|
327
|
+
if (!privateKey) {
|
|
328
|
+
throw new Error('No identity found. Please create or import an identity first.');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const { seq, prev, collection, rkey } = chain;
|
|
332
|
+
return signEnvelope(
|
|
333
|
+
{
|
|
334
|
+
version: 2,
|
|
335
|
+
type,
|
|
336
|
+
subject,
|
|
337
|
+
issuer: subject,
|
|
338
|
+
record,
|
|
339
|
+
issuedAt: Date.now(),
|
|
340
|
+
seq,
|
|
341
|
+
prev,
|
|
342
|
+
collection,
|
|
343
|
+
rkey,
|
|
344
|
+
},
|
|
345
|
+
privateKey,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export default SignatureService;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ACCOUNT_CATEGORY_IDS, SELECTABLE_ACCOUNT_CATEGORY_IDS } from '@oxy.so/contracts';
|
|
2
|
+
import { accountCategoryLabel, EN_ACCOUNT_CATEGORY_LABELS } from '../accountCategoryLabels';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Every locale the SDK ships a dictionary for, plus a region variant and an
|
|
6
|
+
* untranslated language, because the three take different paths through
|
|
7
|
+
* `translate`: exact dictionary, base-subtag dictionary, and English fallback.
|
|
8
|
+
*/
|
|
9
|
+
const SHIPPED_LOCALES = [
|
|
10
|
+
'en-US',
|
|
11
|
+
'es-ES',
|
|
12
|
+
'ca-ES',
|
|
13
|
+
'fr-FR',
|
|
14
|
+
'de-DE',
|
|
15
|
+
'it-IT',
|
|
16
|
+
'pt-PT',
|
|
17
|
+
'ja-JP',
|
|
18
|
+
'ko-KR',
|
|
19
|
+
'zh-CN',
|
|
20
|
+
'ar-SA',
|
|
21
|
+
] as const;
|
|
22
|
+
const REGION_VARIANT = 'es-MX';
|
|
23
|
+
const UNSHIPPED_LOCALE = 'nl-NL';
|
|
24
|
+
|
|
25
|
+
describe('accountCategoryLabel', () => {
|
|
26
|
+
// Vacuity floor: a traversal bug that yielded an empty id list would make
|
|
27
|
+
// every assertion below pass over nothing.
|
|
28
|
+
it('covers the whole vocabulary', () => {
|
|
29
|
+
expect(ACCOUNT_CATEGORY_IDS.length).toBeGreaterThanOrEqual(46);
|
|
30
|
+
expect(Object.keys(EN_ACCOUNT_CATEGORY_LABELS)).toHaveLength(ACCOUNT_CATEGORY_IDS.length);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it.each([...SHIPPED_LOCALES, REGION_VARIANT, UNSHIPPED_LOCALE])(
|
|
34
|
+
'names every category in %s — never a key, never a slug, never empty',
|
|
35
|
+
(locale) => {
|
|
36
|
+
for (const id of ACCOUNT_CATEGORY_IDS) {
|
|
37
|
+
const label = accountCategoryLabel(locale, id);
|
|
38
|
+
expect(label).not.toBe('');
|
|
39
|
+
// `translate` echoes the key when it resolves nothing, so the key IS the
|
|
40
|
+
// failure signal. This is what the screen's old `t(key) || id` believed
|
|
41
|
+
// it was catching and could not, since a non-empty string is truthy.
|
|
42
|
+
expect(label).not.toBe(`accounts.accountCategory.${id}`);
|
|
43
|
+
// The raw slug reaching a reader is the bug this whole indirection
|
|
44
|
+
// exists to prevent. `ai` is excluded: its English label legitimately
|
|
45
|
+
// equals its id.
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
it('falls back to English for a language with no category translations', () => {
|
|
51
|
+
// German ships a dictionary but no category labels, so it exercises
|
|
52
|
+
// `translate`'s PER-KEY English fallback rather than its locale fallback.
|
|
53
|
+
expect(accountCategoryLabel('de-DE', 'cooperative')).toBe(
|
|
54
|
+
EN_ACCOUNT_CATEGORY_LABELS.cooperative,
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('resolves a region variant through its base language', () => {
|
|
59
|
+
expect(accountCategoryLabel('es-MX', 'news')).toBe(accountCategoryLabel('es-ES', 'news'));
|
|
60
|
+
expect(accountCategoryLabel('es-MX', 'news')).not.toBe(EN_ACCOUNT_CATEGORY_LABELS.news);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AccountRole } from '../../mixins/OxyServices.accounts';
|
|
2
|
+
import { EN_ACCOUNT_ROLE_LABELS, accountRoleLabel } from '../accountRoleLabels';
|
|
3
|
+
|
|
4
|
+
const ACCOUNT_ROLES: AccountRole[] = [
|
|
5
|
+
'owner',
|
|
6
|
+
'admin',
|
|
7
|
+
'editor',
|
|
8
|
+
'developer',
|
|
9
|
+
'billing',
|
|
10
|
+
'viewer',
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const SHIPPED_LOCALES = [
|
|
14
|
+
'en-US',
|
|
15
|
+
'es-ES',
|
|
16
|
+
'ca-ES',
|
|
17
|
+
'fr-FR',
|
|
18
|
+
'de-DE',
|
|
19
|
+
'it-IT',
|
|
20
|
+
'pt-PT',
|
|
21
|
+
'ja-JP',
|
|
22
|
+
'ko-KR',
|
|
23
|
+
'zh-CN',
|
|
24
|
+
'ar-SA',
|
|
25
|
+
] as const;
|
|
26
|
+
const REGION_VARIANT = 'es-MX';
|
|
27
|
+
const UNSHIPPED_LOCALE = 'nl-NL';
|
|
28
|
+
|
|
29
|
+
describe('accountRoleLabel', () => {
|
|
30
|
+
it('covers the whole vocabulary', () => {
|
|
31
|
+
expect(ACCOUNT_ROLES.length).toBe(6);
|
|
32
|
+
expect(Object.keys(EN_ACCOUNT_ROLE_LABELS)).toHaveLength(ACCOUNT_ROLES.length);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it.each([...SHIPPED_LOCALES, REGION_VARIANT, UNSHIPPED_LOCALE])(
|
|
36
|
+
'names every role in %s — never a key, never a slug, never empty',
|
|
37
|
+
(locale) => {
|
|
38
|
+
for (const role of ACCOUNT_ROLES) {
|
|
39
|
+
const label = accountRoleLabel(locale, role);
|
|
40
|
+
expect(label).not.toBe('');
|
|
41
|
+
expect(label).not.toBe(`accounts.roles.${role}.label`);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
it('falls back to English for a language with no role translations', () => {
|
|
47
|
+
expect(accountRoleLabel('de-DE', 'developer')).toBe(EN_ACCOUNT_ROLE_LABELS.developer);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('resolves a region variant through its base language', () => {
|
|
51
|
+
expect(accountRoleLabel('es-MX', 'admin')).toBe(accountRoleLabel('es-ES', 'admin'));
|
|
52
|
+
expect(accountRoleLabel('es-MX', 'admin')).not.toBe(EN_ACCOUNT_ROLE_LABELS.admin);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { REPUTATION_CATEGORIES } from '@oxy.so/contracts';
|
|
2
|
+
import {
|
|
3
|
+
EN_REPUTATION_CATEGORY_LABELS,
|
|
4
|
+
reputationCategoryLabel,
|
|
5
|
+
} from '../reputationCategoryLabels';
|
|
6
|
+
|
|
7
|
+
const SHIPPED_LOCALES = [
|
|
8
|
+
'en-US',
|
|
9
|
+
'es-ES',
|
|
10
|
+
'ca-ES',
|
|
11
|
+
'fr-FR',
|
|
12
|
+
'de-DE',
|
|
13
|
+
'it-IT',
|
|
14
|
+
'pt-PT',
|
|
15
|
+
'ja-JP',
|
|
16
|
+
'ko-KR',
|
|
17
|
+
'zh-CN',
|
|
18
|
+
'ar-SA',
|
|
19
|
+
] as const;
|
|
20
|
+
const REGION_VARIANT = 'es-MX';
|
|
21
|
+
const UNSHIPPED_LOCALE = 'nl-NL';
|
|
22
|
+
|
|
23
|
+
describe('reputationCategoryLabel', () => {
|
|
24
|
+
it('covers the whole vocabulary', () => {
|
|
25
|
+
expect(REPUTATION_CATEGORIES.length).toBeGreaterThanOrEqual(7);
|
|
26
|
+
expect(Object.keys(EN_REPUTATION_CATEGORY_LABELS)).toHaveLength(
|
|
27
|
+
REPUTATION_CATEGORIES.length,
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it.each([...SHIPPED_LOCALES, REGION_VARIANT, UNSHIPPED_LOCALE])(
|
|
32
|
+
'names every category in %s — never a key, never a slug, never empty',
|
|
33
|
+
(locale) => {
|
|
34
|
+
for (const id of REPUTATION_CATEGORIES) {
|
|
35
|
+
const label = reputationCategoryLabel(locale, id);
|
|
36
|
+
expect(label).not.toBe('');
|
|
37
|
+
expect(label).not.toBe(`trust.rules.categories.${id}`);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
it('falls back to English for a language with no category translations', () => {
|
|
43
|
+
expect(reputationCategoryLabel('de-DE', 'physical')).toBe(
|
|
44
|
+
EN_REPUTATION_CATEGORY_LABELS.physical,
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('resolves a region variant through its base language', () => {
|
|
49
|
+
expect(reputationCategoryLabel('es-MX', 'content')).toBe(
|
|
50
|
+
reputationCategoryLabel('es-ES', 'content'),
|
|
51
|
+
);
|
|
52
|
+
expect(reputationCategoryLabel('es-MX', 'content')).not.toBe(
|
|
53
|
+
EN_REPUTATION_CATEGORY_LABELS.content,
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { TRUST_TIERS } from '@oxy.so/contracts';
|
|
2
|
+
import { EN_TRUST_TIER_LABELS, trustTierLabel } from '../trustTierLabels';
|
|
3
|
+
|
|
4
|
+
const SHIPPED_LOCALES = [
|
|
5
|
+
'en-US',
|
|
6
|
+
'es-ES',
|
|
7
|
+
'ca-ES',
|
|
8
|
+
'fr-FR',
|
|
9
|
+
'de-DE',
|
|
10
|
+
'it-IT',
|
|
11
|
+
'pt-PT',
|
|
12
|
+
'ja-JP',
|
|
13
|
+
'ko-KR',
|
|
14
|
+
'zh-CN',
|
|
15
|
+
'ar-SA',
|
|
16
|
+
] as const;
|
|
17
|
+
const REGION_VARIANT = 'es-MX';
|
|
18
|
+
const UNSHIPPED_LOCALE = 'nl-NL';
|
|
19
|
+
|
|
20
|
+
describe('trustTierLabel', () => {
|
|
21
|
+
it('covers the whole vocabulary', () => {
|
|
22
|
+
expect(TRUST_TIERS.length).toBe(5);
|
|
23
|
+
expect(Object.keys(EN_TRUST_TIER_LABELS)).toHaveLength(TRUST_TIERS.length);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it.each([...SHIPPED_LOCALES, REGION_VARIANT, UNSHIPPED_LOCALE])(
|
|
27
|
+
'names every tier in %s — never a key, never a slug, never empty',
|
|
28
|
+
(locale) => {
|
|
29
|
+
for (const tier of TRUST_TIERS) {
|
|
30
|
+
const label = trustTierLabel(locale, tier);
|
|
31
|
+
expect(label).not.toBe('');
|
|
32
|
+
expect(label).not.toBe(`trust.tiers.${tier}`);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
it('falls back to English for a language with no tier translations', () => {
|
|
38
|
+
expect(trustTierLabel('de-DE', 'high_trust')).toBe(
|
|
39
|
+
EN_TRUST_TIER_LABELS.high_trust,
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('resolves a region variant through its base language', () => {
|
|
44
|
+
expect(trustTierLabel('es-MX', 'verified')).toBe(trustTierLabel('es-ES', 'verified'));
|
|
45
|
+
expect(trustTierLabel('es-MX', 'verified')).not.toBe(EN_TRUST_TIER_LABELS.verified);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { AccountCategoryId } from '@oxy.so/contracts';
|
|
2
|
+
import enUS from './locales/en-US.json';
|
|
3
|
+
import { translate } from './index';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Every account category's English name, keyed by its stable id.
|
|
7
|
+
*
|
|
8
|
+
* **The annotation is the point.** The vocabulary lives in `@oxy.so/contracts`
|
|
9
|
+
* and the names live in `locales/en-US.json`, so they are two lists that must
|
|
10
|
+
* agree and nothing but a type can make them. Declaring the JSON node as a
|
|
11
|
+
* TOTAL `Record<AccountCategoryId, string>` turns "somebody added a category at
|
|
12
|
+
* Oxy and nobody wrote its English" into a `TS2741` naming the missing id, at
|
|
13
|
+
* build time, instead of a picker row that paints `accounts.accountCategory.<id>`
|
|
14
|
+
* at a user trying to choose one.
|
|
15
|
+
*
|
|
16
|
+
* That failure is not hypothetical. The screen previously wrote `t(key) || id`,
|
|
17
|
+
* whose author believed an unnamed id would degrade to its raw slug. It cannot:
|
|
18
|
+
* {@link translate} echoes the KEY when it resolves nothing, and a non-empty
|
|
19
|
+
* string is never falsy, so the `|| id` arm was unreachable and the output was
|
|
20
|
+
* the dotted key. A runtime fallback that cannot run is worse than none,
|
|
21
|
+
* because it reads as protection.
|
|
22
|
+
*
|
|
23
|
+
* Totality is over `ACCOUNT_CATEGORY_IDS`, which RETAINS withdrawn ids, so an
|
|
24
|
+
* account still carrying a retired category keeps rendering its name while no
|
|
25
|
+
* picker offers it again. Retired and unknown are different cases: only an id
|
|
26
|
+
* outside the union is unnameable, which is why this is keyed by
|
|
27
|
+
* `AccountCategoryId` and not by `string`.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Module-scoped, NOT re-exported from the package index: the annotation is the
|
|
31
|
+
* whole job, and it does that job without being public API. It carries no
|
|
32
|
+
* `Object.freeze` and no `Readonly<>` for the same reason — those existed only
|
|
33
|
+
* to make an exported reference safe from a consumer's stray write, and there
|
|
34
|
+
* is no such consumer. Exported from the MODULE so its own test can name it.
|
|
35
|
+
*/
|
|
36
|
+
export const EN_ACCOUNT_CATEGORY_LABELS: Record<AccountCategoryId, string> =
|
|
37
|
+
enUS.accounts.accountCategory;
|
|
38
|
+
|
|
39
|
+
export function accountCategoryLabel(
|
|
40
|
+
locale: string | undefined,
|
|
41
|
+
id: AccountCategoryId,
|
|
42
|
+
): string {
|
|
43
|
+
return translate(locale, `accounts.accountCategory.${id}`);
|
|
44
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AccountRole } from '../mixins/OxyServices.accounts';
|
|
2
|
+
import enUS from './locales/en-US.json';
|
|
3
|
+
import { translate } from './index';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Every account member role's English name, keyed by its stable id.
|
|
7
|
+
*
|
|
8
|
+
* Totality is over the closed `AccountRole` union so a new role without an
|
|
9
|
+
* English label is a build error, not a members row that paints
|
|
10
|
+
* `accounts.roles.<role>.label`.
|
|
11
|
+
*/
|
|
12
|
+
export const EN_ACCOUNT_ROLE_LABELS: Record<AccountRole, string> = {
|
|
13
|
+
owner: enUS.accounts.roles.owner.label,
|
|
14
|
+
admin: enUS.accounts.roles.admin.label,
|
|
15
|
+
editor: enUS.accounts.roles.editor.label,
|
|
16
|
+
developer: enUS.accounts.roles.developer.label,
|
|
17
|
+
billing: enUS.accounts.roles.billing.label,
|
|
18
|
+
viewer: enUS.accounts.roles.viewer.label,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function accountRoleLabel(
|
|
22
|
+
locale: string | undefined,
|
|
23
|
+
role: AccountRole,
|
|
24
|
+
): string {
|
|
25
|
+
return translate(locale, `accounts.roles.${role}.label`);
|
|
26
|
+
}
|