@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,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two questions an account chooser asks of an account-graph node: is this
|
|
3
|
+
* kind switchable at all, and may THIS caller become it.
|
|
4
|
+
*
|
|
5
|
+
* Pure and I/O-free. They live here rather than beside the surfaces that ask
|
|
6
|
+
* them because there is more than one such surface — the Console's workspace
|
|
7
|
+
* tree, the Accounts app's managed-account rows — and a second enumeration of
|
|
8
|
+
* switch targets is a second place for the rule to go missing, which is
|
|
9
|
+
* precisely how the Console went on offering `channel` rows after the rule
|
|
10
|
+
* learned to drop them.
|
|
11
|
+
*
|
|
12
|
+
* The DEVICE switcher no longer asks anything here: it renders the server's
|
|
13
|
+
* device directory (ADR 0002, `deviceDirectory.ts`), whose `available` field is
|
|
14
|
+
* the server's own authorization verdict. These predicates answer a different
|
|
15
|
+
* question — one about the caller's account GRAPH, which is a list of accounts
|
|
16
|
+
* to manage, not a list of identities the device can become.
|
|
17
|
+
*/
|
|
18
|
+
import { isOperatorSwitchTargetKind } from '@oxy.so/contracts';
|
|
19
|
+
/**
|
|
20
|
+
* Whether the caller can BECOME this account — the one question every account
|
|
21
|
+
* switcher asks, answered here so no surface has to re-derive it.
|
|
22
|
+
*
|
|
23
|
+
* Two independent grounds, either of which suffices:
|
|
24
|
+
*
|
|
25
|
+
* - **It is already the caller's own identity** (`relationship: 'self'`).
|
|
26
|
+
* `GET /accounts` resolves its caller through `resolveOperatorId`, so `self`
|
|
27
|
+
* is the HUMAN operator's personal account even while they are operating an
|
|
28
|
+
* org — never the operated account. Kind is irrelevant on this ground: the
|
|
29
|
+
* caller IS that account, so returning to it asks the server for nothing.
|
|
30
|
+
* - **The server will mint a session for it** — `isOperatorSwitchTargetKind(kind)`
|
|
31
|
+
* is the exact predicate `POST /accounts/:id/switch` enforces, so a row
|
|
32
|
+
* offered on this ground is never a dead button.
|
|
33
|
+
*
|
|
34
|
+
* `isOperatorSwitchTargetKind` ALONE is not this question, and reaching for it
|
|
35
|
+
* directly is the mistake this function exists to prevent: it is false for
|
|
36
|
+
* `personal` as well as `channel`, so a switcher gated on it alone renders an
|
|
37
|
+
* empty list rather than a filtered one. Equally, `kind !== 'channel'` is not
|
|
38
|
+
* this question either — it silently admits every kind invented after it was
|
|
39
|
+
* written, which is the same trap the kind predicates were introduced to close
|
|
40
|
+
* on the server.
|
|
41
|
+
*
|
|
42
|
+
* And it is the OPERATOR predicate, never `isDelegatedActAsEligibleKind`. The
|
|
43
|
+
* two differ only on `bot`, so the delegated one produces a list that looks
|
|
44
|
+
* right and contains one row too many — a seat inside the identity that exists
|
|
45
|
+
* to act while nobody is present. That is not a hypothetical: it put a live bot
|
|
46
|
+
* session on a person's own device, beside their personal login.
|
|
47
|
+
*
|
|
48
|
+
* Takes a structural subset rather than a whole {@link AccountNode} so a caller
|
|
49
|
+
* holding an already-projected row can ask it too.
|
|
50
|
+
*/
|
|
51
|
+
export function isSwitchTargetAccount(node) {
|
|
52
|
+
return node.relationship === 'self' || isOperatorSwitchTargetKind(node.kind);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether the caller may switch INTO this account — the server-side
|
|
56
|
+
* `account:act_as` gate plus the structural {@link isSwitchTargetAccount} rule.
|
|
57
|
+
*
|
|
58
|
+
* `relationship: 'self'` always passes (returning to the caller's own personal
|
|
59
|
+
* account). Every other ground requires a switch-eligible kind AND
|
|
60
|
+
* `account:act_as` in the resolved membership permissions. When permissions are
|
|
61
|
+
* absent but the relationship is `owner`, the owner baseline is assumed — the
|
|
62
|
+
* API always resolves effective permissions for owned accounts, but test
|
|
63
|
+
* fixtures and stale rows may omit the membership blob.
|
|
64
|
+
*/
|
|
65
|
+
export function canSwitchIntoAccount(node) {
|
|
66
|
+
if (node.relationship === 'self') {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (!isSwitchTargetAccount(node)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const permissions = node.callerMembership?.permissions;
|
|
73
|
+
if (permissions) {
|
|
74
|
+
return permissions.includes('account:act_as');
|
|
75
|
+
}
|
|
76
|
+
return node.relationship === 'owner';
|
|
77
|
+
}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted auth state — ONE shape, web + native.
|
|
3
|
+
*
|
|
4
|
+
* The zero-cookie device transport persists the device credential per ORIGIN so
|
|
5
|
+
* a reload restores the session locally without a redirect: `deviceId` +
|
|
6
|
+
* `deviceSecret` mint a fresh access token via `POST /session/device/token`.
|
|
7
|
+
* This module is the storage seam: a tiny `load / save / clear` interface plus
|
|
8
|
+
* platform factories, so the cold boot (`sessionColdBoot`) and the unified re-mint
|
|
9
|
+
* handler (`refresh.ts`) never touch a platform storage API directly.
|
|
10
|
+
*
|
|
11
|
+
* Platform-agnostic — the native factory takes an INJECTED key/value store
|
|
12
|
+
* (`@oxy.so/services` passes a SecureStore-backed adapter) so `@oxy.so/core`
|
|
13
|
+
* never imports `expo-secure-store`. The web factory is self-contained
|
|
14
|
+
* (`localStorage`) and degrades to in-memory when storage is unavailable
|
|
15
|
+
* (sandboxed iframe `SecurityError`, private-mode quota, SSR).
|
|
16
|
+
*
|
|
17
|
+
* ESM-safe (no `require()`).
|
|
18
|
+
*/
|
|
19
|
+
import { logger } from '../logger/index.js';
|
|
20
|
+
/**
|
|
21
|
+
* Versioned DURABLE storage key. Holds ONLY the small, re-mint-critical fields
|
|
22
|
+
* (`sessionId`, `userId`, `deviceId`, `deviceSecret`) — never the large JWT
|
|
23
|
+
* `accessToken`. Keeping this blob small (<2KB) matters on Android
|
|
24
|
+
* `expo-secure-store`, whose backing store can silently fail to persist an
|
|
25
|
+
* oversize value; bundling the token here previously took the mint credential
|
|
26
|
+
* down with it on every write, losing the session on cold restart.
|
|
27
|
+
*
|
|
28
|
+
* The `.v1` suffix lets a future shape change ship a `.v2` key without reading a
|
|
29
|
+
* stale/incompatible `.v1` blob. Distinct from the `oxy_shared_*` keychain keys
|
|
30
|
+
* in `KeyManager`, so it never collides.
|
|
31
|
+
*
|
|
32
|
+
* BACK-COMPAT: pre-split builds wrote the WHOLE state (including `accessToken` /
|
|
33
|
+
* `expiresAt`) into this single key. `load()` still reads those token fields
|
|
34
|
+
* from here when the warm key ({@link AUTH_STATE_TOKEN_STORAGE_KEY}) is absent,
|
|
35
|
+
* so upgrading users are not signed out; the next `save()` splits them apart.
|
|
36
|
+
*/
|
|
37
|
+
export const AUTH_STATE_STORAGE_KEY = 'oxy.auth.v1';
|
|
38
|
+
/**
|
|
39
|
+
* Versioned BEST-EFFORT warm-token storage key. Holds the short-lived
|
|
40
|
+
* `{ accessToken, expiresAt }` pair only. Its write is genuinely non-fatal — a
|
|
41
|
+
* failure (quota / oversize keychain value) is swallowed because the session is
|
|
42
|
+
* fully re-mintable from the durable `deviceSecret`. Kept separate from
|
|
43
|
+
* {@link AUTH_STATE_STORAGE_KEY} so a failed token write can NEVER abort or
|
|
44
|
+
* corrupt the durable credential write.
|
|
45
|
+
*/
|
|
46
|
+
export const AUTH_STATE_TOKEN_STORAGE_KEY = 'oxy.auth.token.v1';
|
|
47
|
+
/**
|
|
48
|
+
* Parse + shape-validate a stored blob. Returns `null` for anything that is
|
|
49
|
+
* not a well-formed {@link PersistedAuthState} (absent, malformed JSON, wrong
|
|
50
|
+
* types) so a corrupt entry degrades to "signed out" rather than throwing.
|
|
51
|
+
*/
|
|
52
|
+
function deserialize(raw) {
|
|
53
|
+
if (!raw) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const candidate = parsed;
|
|
67
|
+
const hasDeviceCredential = typeof candidate.deviceId === 'string' &&
|
|
68
|
+
candidate.deviceId.length > 0 &&
|
|
69
|
+
typeof candidate.deviceSecret === 'string' &&
|
|
70
|
+
candidate.deviceSecret.length > 0;
|
|
71
|
+
const hasSessionIdentity = typeof candidate.sessionId === 'string' &&
|
|
72
|
+
typeof candidate.userId === 'string' &&
|
|
73
|
+
candidate.sessionId.length > 0 &&
|
|
74
|
+
candidate.userId.length > 0;
|
|
75
|
+
// Device-only bootstrap (post join, pre-sign-in): durable credential without session.
|
|
76
|
+
if (!hasSessionIdentity && !hasDeviceCredential) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const state = {
|
|
80
|
+
sessionId: hasSessionIdentity ? candidate.sessionId : '',
|
|
81
|
+
userId: hasSessionIdentity ? candidate.userId : '',
|
|
82
|
+
};
|
|
83
|
+
if (typeof candidate.deviceId === 'string' && candidate.deviceId.length > 0) {
|
|
84
|
+
state.deviceId = candidate.deviceId;
|
|
85
|
+
}
|
|
86
|
+
if (typeof candidate.deviceSecret === 'string' && candidate.deviceSecret.length > 0) {
|
|
87
|
+
state.deviceSecret = candidate.deviceSecret;
|
|
88
|
+
}
|
|
89
|
+
if (typeof candidate.accessToken === 'string' && candidate.accessToken.length > 0) {
|
|
90
|
+
state.accessToken = candidate.accessToken;
|
|
91
|
+
}
|
|
92
|
+
if (typeof candidate.expiresAt === 'string' && candidate.expiresAt.length > 0) {
|
|
93
|
+
state.expiresAt = candidate.expiresAt;
|
|
94
|
+
}
|
|
95
|
+
return state;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Parse the best-effort warm-token blob. Returns `null` for anything not a
|
|
99
|
+
* well-formed object so a corrupt warm entry simply forgoes the warm-boot
|
|
100
|
+
* optimization (the durable credential re-mints a fresh token).
|
|
101
|
+
*/
|
|
102
|
+
function parseWarmToken(raw) {
|
|
103
|
+
if (!raw) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
let parsed;
|
|
107
|
+
try {
|
|
108
|
+
parsed = JSON.parse(raw);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const candidate = parsed;
|
|
117
|
+
const warm = {};
|
|
118
|
+
if (typeof candidate.accessToken === 'string' && candidate.accessToken.length > 0) {
|
|
119
|
+
warm.accessToken = candidate.accessToken;
|
|
120
|
+
}
|
|
121
|
+
if (typeof candidate.expiresAt === 'string' && candidate.expiresAt.length > 0) {
|
|
122
|
+
warm.expiresAt = candidate.expiresAt;
|
|
123
|
+
}
|
|
124
|
+
return warm;
|
|
125
|
+
}
|
|
126
|
+
/** Serialize ONLY the small, re-mint-critical fields for the durable key. */
|
|
127
|
+
function serializeDurable(state) {
|
|
128
|
+
const durable = {
|
|
129
|
+
sessionId: state.sessionId,
|
|
130
|
+
userId: state.userId,
|
|
131
|
+
};
|
|
132
|
+
if (state.deviceId) {
|
|
133
|
+
durable.deviceId = state.deviceId;
|
|
134
|
+
}
|
|
135
|
+
if (state.deviceSecret) {
|
|
136
|
+
durable.deviceSecret = state.deviceSecret;
|
|
137
|
+
}
|
|
138
|
+
return JSON.stringify(durable);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Serialize the warm-token blob, or `null` when there is no token to persist
|
|
142
|
+
* (so the caller clears the warm key rather than writing an empty object).
|
|
143
|
+
*/
|
|
144
|
+
function serializeWarmToken(state) {
|
|
145
|
+
const warm = {};
|
|
146
|
+
if (state.accessToken) {
|
|
147
|
+
warm.accessToken = state.accessToken;
|
|
148
|
+
}
|
|
149
|
+
if (state.expiresAt) {
|
|
150
|
+
warm.expiresAt = state.expiresAt;
|
|
151
|
+
}
|
|
152
|
+
if (!warm.accessToken && !warm.expiresAt) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return JSON.stringify(warm);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Compose the unchanged {@link PersistedAuthState} return shape from the two
|
|
159
|
+
* on-disk keys. `accessToken` / `expiresAt` come from the warm key when it is
|
|
160
|
+
* present; when the warm key is ABSENT the token fields fall back to whatever
|
|
161
|
+
* the durable blob carried — the pre-split combined `oxy.auth.v1` blob (BACK-COMPAT).
|
|
162
|
+
*/
|
|
163
|
+
function composeState(durableRaw, warmRaw) {
|
|
164
|
+
const state = deserialize(durableRaw);
|
|
165
|
+
if (!state) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
if (warmRaw !== null) {
|
|
169
|
+
// New split layout: the warm key is authoritative for the token fields.
|
|
170
|
+
// Drop anything the durable blob may have carried, then overlay the warm
|
|
171
|
+
// values (a warm key with no token → the session simply has no warm token).
|
|
172
|
+
delete state.accessToken;
|
|
173
|
+
delete state.expiresAt;
|
|
174
|
+
const warm = parseWarmToken(warmRaw);
|
|
175
|
+
if (warm?.accessToken) {
|
|
176
|
+
state.accessToken = warm.accessToken;
|
|
177
|
+
}
|
|
178
|
+
if (warm?.expiresAt) {
|
|
179
|
+
state.expiresAt = warm.expiresAt;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// else: BACK-COMPAT — the warm key is absent, so `deserialize` already applied
|
|
183
|
+
// any `accessToken` / `expiresAt` from the old combined blob.
|
|
184
|
+
return state;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* A process-lifetime, in-memory {@link AuthStateStore}. Used directly for
|
|
188
|
+
* tests/SSR and as the degraded fallback of the web store when `localStorage`
|
|
189
|
+
* is unreachable. Not durable across reloads — that is acceptable for the
|
|
190
|
+
* fallback because the alternative (throwing) would break cold boot entirely.
|
|
191
|
+
*/
|
|
192
|
+
export function createMemoryAuthStateStore() {
|
|
193
|
+
let current = null;
|
|
194
|
+
return {
|
|
195
|
+
load: async () => current,
|
|
196
|
+
save: async (state) => {
|
|
197
|
+
// Memory IS this store's durability backing — the write always lands.
|
|
198
|
+
current = state;
|
|
199
|
+
return true;
|
|
200
|
+
},
|
|
201
|
+
clear: async () => {
|
|
202
|
+
current = null;
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Read the ambient `localStorage`, tolerating the case where merely ACCESSING
|
|
208
|
+
* `window.localStorage` throws. In a sandboxed / cross-origin iframe the getter
|
|
209
|
+
* itself raises `SecurityError` (not the method calls), so the access must be
|
|
210
|
+
* inside the try. Returns `null` when storage is unavailable.
|
|
211
|
+
*/
|
|
212
|
+
function safeGetLocalStorage() {
|
|
213
|
+
try {
|
|
214
|
+
if (typeof globalThis === 'undefined') {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
const store = globalThis.localStorage;
|
|
218
|
+
return store ?? null;
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* A `localStorage`-backed {@link AuthStateStore} split across the durable
|
|
226
|
+
* {@link AUTH_STATE_STORAGE_KEY} (mint credential) and the best-effort
|
|
227
|
+
* {@link AUTH_STATE_TOKEN_STORAGE_KEY} (warm access token).
|
|
228
|
+
*
|
|
229
|
+
* Resilience:
|
|
230
|
+
* - If `localStorage` is unreachable (sandboxed-iframe `SecurityError`, SSR),
|
|
231
|
+
* the whole store degrades to an in-memory {@link createMemoryAuthStateStore}
|
|
232
|
+
* for this page's lifetime — never throws on construction.
|
|
233
|
+
* - Individual `getItem`/`setItem`/`removeItem` are each wrapped: a read that
|
|
234
|
+
* throws yields `null`; a write that throws (quota, private mode) is
|
|
235
|
+
* swallowed. The re-mint lane treats a failed persist as "no durable state"
|
|
236
|
+
* rather than crashing.
|
|
237
|
+
*/
|
|
238
|
+
export function createWebAuthStateStore() {
|
|
239
|
+
const storage = safeGetLocalStorage();
|
|
240
|
+
if (!storage) {
|
|
241
|
+
return createMemoryAuthStateStore();
|
|
242
|
+
}
|
|
243
|
+
// In-memory mirror so a FAILED persist (quota / private mode / locked store)
|
|
244
|
+
// does not silently lose the session for this page's lifetime. `undefined`
|
|
245
|
+
// means "never written this session" → fall back to storage; any set value
|
|
246
|
+
// (including `null` after clear) is authoritative and preferred over storage.
|
|
247
|
+
let sessionMirror;
|
|
248
|
+
return {
|
|
249
|
+
load: async () => {
|
|
250
|
+
if (sessionMirror !== undefined) {
|
|
251
|
+
return sessionMirror;
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
return composeState(storage.getItem(AUTH_STATE_STORAGE_KEY), storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY));
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
save: async (state) => {
|
|
261
|
+
sessionMirror = state; // mirror FIRST — authoritative even if persist fails
|
|
262
|
+
// Durable credential FIRST, then VERIFY it landed. The in-memory mirror
|
|
263
|
+
// keeps the session live for this page, but a failed DURABLE write means
|
|
264
|
+
// the mint credential will NOT survive a reload — surface it, never swallow.
|
|
265
|
+
let durablePersisted = false;
|
|
266
|
+
try {
|
|
267
|
+
const durableJson = serializeDurable(state);
|
|
268
|
+
storage.setItem(AUTH_STATE_STORAGE_KEY, durableJson);
|
|
269
|
+
durablePersisted = storage.getItem(AUTH_STATE_STORAGE_KEY) === durableJson;
|
|
270
|
+
if (!durablePersisted) {
|
|
271
|
+
logger.error('[authStateStore] durable credential read-back mismatch after save — the device credential did not persist; the session survives this process via the in-memory mirror but will be lost on reload', undefined, { component: 'authStateStore' });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
logger.error('[authStateStore] durable credential persist threw — the device credential did not persist; the session survives this process via the in-memory mirror but will be lost on reload', error, { component: 'authStateStore' });
|
|
276
|
+
}
|
|
277
|
+
// Warm token AFTER, best-effort. Its failure is genuinely non-fatal (the
|
|
278
|
+
// durable credential re-mints a fresh token) and must never abort or
|
|
279
|
+
// corrupt the durable write above.
|
|
280
|
+
try {
|
|
281
|
+
const warmJson = serializeWarmToken(state);
|
|
282
|
+
if (warmJson) {
|
|
283
|
+
storage.setItem(AUTH_STATE_TOKEN_STORAGE_KEY, warmJson);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// Quota / private-mode / disabled storage — non-fatal warm-boot loss only.
|
|
291
|
+
}
|
|
292
|
+
// Report ONLY the durable-credential landing; the warm-token outcome above
|
|
293
|
+
// is intentionally excluded (it is a best-effort optimization).
|
|
294
|
+
return durablePersisted;
|
|
295
|
+
},
|
|
296
|
+
clear: async () => {
|
|
297
|
+
sessionMirror = null;
|
|
298
|
+
try {
|
|
299
|
+
storage.removeItem(AUTH_STATE_STORAGE_KEY);
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
// Non-fatal — see save().
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Non-fatal — see save().
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* A native {@link AuthStateStore} over an injected async key/value store.
|
|
315
|
+
*
|
|
316
|
+
* `@oxy.so/core` never imports `expo-secure-store`; `@oxy.so/services` constructs
|
|
317
|
+
* the SecureStore-backed adapter and passes it here. Persistence is split across
|
|
318
|
+
* the durable {@link AUTH_STATE_STORAGE_KEY} (mint credential) and the
|
|
319
|
+
* best-effort {@link AUTH_STATE_TOKEN_STORAGE_KEY} (warm access token) — the
|
|
320
|
+
* durable write is read-back-verified and its failure surfaced (not swallowed),
|
|
321
|
+
* while the warm-token write and all reads degrade gracefully exactly like the
|
|
322
|
+
* web store.
|
|
323
|
+
*/
|
|
324
|
+
export function createNativeAuthStateStore(storage) {
|
|
325
|
+
// Same in-memory mirror as the web store — a locked/failed SecureStore write
|
|
326
|
+
// must not silently lose the session for the app's lifetime.
|
|
327
|
+
let sessionMirror;
|
|
328
|
+
return {
|
|
329
|
+
load: async () => {
|
|
330
|
+
if (sessionMirror !== undefined) {
|
|
331
|
+
return sessionMirror;
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
const [durableRaw, warmRaw] = await Promise.all([
|
|
335
|
+
storage.getItem(AUTH_STATE_STORAGE_KEY),
|
|
336
|
+
storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY),
|
|
337
|
+
]);
|
|
338
|
+
return composeState(durableRaw, warmRaw);
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
save: async (state) => {
|
|
345
|
+
sessionMirror = state;
|
|
346
|
+
// Durable credential FIRST, then VERIFY. On Android SecureStore an
|
|
347
|
+
// oversize/failed write can resolve WITHOUT throwing, so a read-back is the
|
|
348
|
+
// only reliable proof. The mirror keeps the session live for this app run,
|
|
349
|
+
// but a failed DURABLE write means the mint credential will NOT survive a
|
|
350
|
+
// cold restart — surface it, never swallow.
|
|
351
|
+
let durablePersisted = false;
|
|
352
|
+
try {
|
|
353
|
+
const durableJson = serializeDurable(state);
|
|
354
|
+
await storage.setItem(AUTH_STATE_STORAGE_KEY, durableJson);
|
|
355
|
+
durablePersisted = (await storage.getItem(AUTH_STATE_STORAGE_KEY)) === durableJson;
|
|
356
|
+
if (!durablePersisted) {
|
|
357
|
+
logger.error('[authStateStore] durable credential read-back mismatch after save — the device credential did not persist (likely oversize SecureStore value); the session survives this app run via the in-memory mirror but will be lost on cold restart', undefined, { component: 'authStateStore' });
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
logger.error('[authStateStore] durable credential persist threw — the device credential did not persist; the session survives this app run via the in-memory mirror but will be lost on cold restart', error, { component: 'authStateStore' });
|
|
362
|
+
}
|
|
363
|
+
// Warm token AFTER, best-effort. Its failure is genuinely non-fatal (the
|
|
364
|
+
// durable credential re-mints a fresh token) and must never abort or
|
|
365
|
+
// corrupt the durable write above.
|
|
366
|
+
try {
|
|
367
|
+
const warmJson = serializeWarmToken(state);
|
|
368
|
+
if (warmJson) {
|
|
369
|
+
await storage.setItem(AUTH_STATE_TOKEN_STORAGE_KEY, warmJson);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
await storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Locked / oversize keychain — non-fatal warm-boot loss only.
|
|
377
|
+
}
|
|
378
|
+
// Report ONLY the durable-credential landing; the warm-token outcome above
|
|
379
|
+
// is intentionally excluded (it is a best-effort optimization).
|
|
380
|
+
return durablePersisted;
|
|
381
|
+
},
|
|
382
|
+
clear: async () => {
|
|
383
|
+
sessionMirror = null;
|
|
384
|
+
try {
|
|
385
|
+
await storage.removeItem(AUTH_STATE_STORAGE_KEY);
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
// Non-fatal.
|
|
389
|
+
}
|
|
390
|
+
try {
|
|
391
|
+
await storage.removeItem(AUTH_STATE_TOKEN_STORAGE_KEY);
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
// Non-fatal.
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SessionClient } from './SessionClient.js';
|
|
2
|
+
import { createSessionClientHost } from './sessionClientHost.js';
|
|
3
|
+
/**
|
|
4
|
+
* Wires a `SessionClient` over the given `OxyServices` instance: builds the
|
|
5
|
+
* `SessionClientHost` adapter and passes it through together with a
|
|
6
|
+
* caller-supplied `TokenTransport`.
|
|
7
|
+
*
|
|
8
|
+
* The transport is a required parameter (not constructed here) because it is
|
|
9
|
+
* the one piece of this integration that is NOT platform-agnostic: `services`
|
|
10
|
+
* branches native (shared-keychain sign-in) vs. web (silent sign-in), while
|
|
11
|
+
* `auth-sdk` is web-only. Each consumer builds its own transport and passes
|
|
12
|
+
* it in; this factory only wires the platform-agnostic parts (host + client)
|
|
13
|
+
* so neither consumer re-implements them.
|
|
14
|
+
*
|
|
15
|
+
* The host is returned alongside the client (not just the client) so the
|
|
16
|
+
* caller can call `host.setCurrentAccountId(...)` as the active account
|
|
17
|
+
* changes.
|
|
18
|
+
*
|
|
19
|
+
* `socketFactory` is the statically-injected `socket.io-client` `io` export.
|
|
20
|
+
* Consumers that bundle socket.io-client as a real dependency pass it so
|
|
21
|
+
* realtime sync never depends on core's lazy dynamic import of a bare
|
|
22
|
+
* specifier (bundler-fragile in Metro/Expo-web and Vite against the published
|
|
23
|
+
* dist). When omitted, the client falls back to the lazy loader.
|
|
24
|
+
*/
|
|
25
|
+
export function createSessionClient(oxyServices, transport, socketFactory) {
|
|
26
|
+
const host = createSessionClientHost(oxyServices);
|
|
27
|
+
const client = new SessionClient(host, { transport, socketFactory });
|
|
28
|
+
return { client, host };
|
|
29
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { getAccountDisplayName } from '../utils/accountUtils.js';
|
|
2
|
+
import { getNormalizedUserHandle } from '../utils/userHandle.js';
|
|
3
|
+
/** Resolve one wire context under the principal it hangs off. */
|
|
4
|
+
function toDeviceContext(principal, context) {
|
|
5
|
+
return {
|
|
6
|
+
contextId: context.id,
|
|
7
|
+
actor: {
|
|
8
|
+
principalId: principal.id,
|
|
9
|
+
userId: principal.userId,
|
|
10
|
+
authuser: principal.authuser,
|
|
11
|
+
profile: principal.user,
|
|
12
|
+
},
|
|
13
|
+
subject: {
|
|
14
|
+
accountId: context.accountId,
|
|
15
|
+
kind: context.kind,
|
|
16
|
+
relationship: context.relationship,
|
|
17
|
+
profile: context.account,
|
|
18
|
+
onDevice: context.onDevice,
|
|
19
|
+
available: context.available,
|
|
20
|
+
lastUsedAt: context.lastUsedAt,
|
|
21
|
+
},
|
|
22
|
+
isDelegated: context.accountId !== principal.userId,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve one context by its id.
|
|
27
|
+
*
|
|
28
|
+
* The search is over `(principal, context)` PAIRS, not over accounts: the same
|
|
29
|
+
* `accountId` legitimately appears under two principals on a shared device, and
|
|
30
|
+
* matching on the account would hand back whichever person happened to be
|
|
31
|
+
* enumerated first.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveDeviceContext(directory, contextId) {
|
|
34
|
+
if (directory === null) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
for (const principal of directory.principals) {
|
|
38
|
+
for (const context of principal.contexts) {
|
|
39
|
+
if (context.id === contextId) {
|
|
40
|
+
return toDeviceContext(principal, context);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The directory as the switcher renders it: people, each with what they may
|
|
48
|
+
* become.
|
|
49
|
+
*
|
|
50
|
+
* A principal with no contexts is kept rather than dropped. It is a real state
|
|
51
|
+
* — a person whose every context was removed while they remain on the device —
|
|
52
|
+
* and rendering them with nothing under them is how "sign out of this person"
|
|
53
|
+
* stays reachable. Silently omitting them would strand the row.
|
|
54
|
+
*/
|
|
55
|
+
export function projectDevicePrincipals(directory) {
|
|
56
|
+
if (directory === null) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
return directory.principals.map((principal) => ({
|
|
60
|
+
principalId: principal.id,
|
|
61
|
+
userId: principal.userId,
|
|
62
|
+
authuser: principal.authuser,
|
|
63
|
+
profile: principal.user,
|
|
64
|
+
contexts: principal.contexts.map((context) => toDeviceContext(principal, context)),
|
|
65
|
+
isActive: directory.activeContextId !== null &&
|
|
66
|
+
principal.contexts.some((context) => context.id === directory.activeContextId),
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The device's active context, or `null`.
|
|
71
|
+
*
|
|
72
|
+
* `null` is a real state, not an error: a device with every context removed, or
|
|
73
|
+
* one whose active context was healed away, has none. It is also the answer when
|
|
74
|
+
* `activeContextId` names a row no principal holds — a directory that
|
|
75
|
+
* disagreed with itself, which resolves to "nothing is active" rather than to a
|
|
76
|
+
* guess.
|
|
77
|
+
*/
|
|
78
|
+
export function resolveActiveContext(directory) {
|
|
79
|
+
if (directory === null || directory.activeContextId === null) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return resolveDeviceContext(directory, directory.activeContextId);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The name a directory row renders: the API's `displayName` when it has one,
|
|
86
|
+
* otherwise the normalized handle, otherwise the localized unnamed sentinel.
|
|
87
|
+
*
|
|
88
|
+
* The identity contract's `displayName ?? handle`, and deliberately not
|
|
89
|
+
* `getAccountDisplayName`'s multi-field chain — that one is for LOCAL account
|
|
90
|
+
* surfaces, and the directory profile is an API DTO whose `name.displayName`
|
|
91
|
+
* the server already composed or deliberately omitted. `getAccountDisplayName`
|
|
92
|
+
* appears here only for its `null` case, which is the sentinel.
|
|
93
|
+
*/
|
|
94
|
+
export function directoryDisplayName(profile, locale) {
|
|
95
|
+
const displayName = profile.name?.displayName?.trim();
|
|
96
|
+
if (displayName) {
|
|
97
|
+
return displayName;
|
|
98
|
+
}
|
|
99
|
+
return getNormalizedUserHandle(profile) ?? getAccountDisplayName(null, locale);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A directory row's `@handle`, or `null` when the profile carries no usable
|
|
103
|
+
* username.
|
|
104
|
+
*
|
|
105
|
+
* The directory profile has no email — by design, it is the minimum that
|
|
106
|
+
* renders a row — so the handle is the secondary line, never a synthesized
|
|
107
|
+
* `username@oxy.so` address.
|
|
108
|
+
*/
|
|
109
|
+
export function directoryHandle(profile) {
|
|
110
|
+
return getNormalizedUserHandle(profile);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Whether a switcher may offer this row — the one question it asks, answered
|
|
114
|
+
* here so no surface has to re-derive it.
|
|
115
|
+
*
|
|
116
|
+
* It is deliberately a single field. `available` is the server's complete
|
|
117
|
+
* verdict (see {@link DeviceContextSubject.available}), and switchability is an
|
|
118
|
+
* authorization question the client must READ, never recompute; this exists to
|
|
119
|
+
* name the field that answers it, not to combine several.
|
|
120
|
+
*
|
|
121
|
+
* `onDevice` is NOT part of the question and composing the two is the mistake
|
|
122
|
+
* this function exists to prevent, in both directions. `onDevice: false` is an
|
|
123
|
+
* ordinary reachable context whose session is minted on first activation, so
|
|
124
|
+
* requiring it hides every organization the person has not used here yet.
|
|
125
|
+
* `onDevice: true` does not imply activatable either: when a principal's own
|
|
126
|
+
* personal session dies, their delegated contexts keep live sessions of their
|
|
127
|
+
* own and still cannot be activated, so `available || onDevice` would render a
|
|
128
|
+
* row the server answers with 403 and then heals away.
|
|
129
|
+
*
|
|
130
|
+
* Takes a structural subset so a caller holding a raw `DeviceAccountContext`
|
|
131
|
+
* from the wire can ask it without resolving the pair first.
|
|
132
|
+
*/
|
|
133
|
+
export function canActivateContext(context) {
|
|
134
|
+
return context.available;
|
|
135
|
+
}
|