@oxyhq/core 18.0.0 → 19.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.
Files changed (43) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/i18n/locales/en-US.json +48 -5
  3. package/dist/cjs/i18n/locales/es-ES.json +48 -5
  4. package/dist/cjs/i18n/locales/locales/en-US.json +48 -5
  5. package/dist/cjs/i18n/locales/locales/es-ES.json +48 -5
  6. package/dist/cjs/index.js +10 -6
  7. package/dist/cjs/mixins/OxyServices.accounts.js +27 -2
  8. package/dist/cjs/mixins/OxyServices.user.js +14 -20
  9. package/dist/cjs/server/index.js +8 -2
  10. package/dist/cjs/server/userInvalidation.js +6 -28
  11. package/dist/cjs/utils/identityCacheSweep.js +97 -0
  12. package/dist/esm/.tsbuildinfo +1 -1
  13. package/dist/esm/i18n/locales/en-US.json +48 -5
  14. package/dist/esm/i18n/locales/es-ES.json +48 -5
  15. package/dist/esm/i18n/locales/locales/en-US.json +48 -5
  16. package/dist/esm/i18n/locales/locales/es-ES.json +48 -5
  17. package/dist/esm/index.js +1 -1
  18. package/dist/esm/mixins/OxyServices.accounts.js +22 -1
  19. package/dist/esm/mixins/OxyServices.user.js +14 -20
  20. package/dist/esm/server/index.js +5 -1
  21. package/dist/esm/server/userInvalidation.js +5 -26
  22. package/dist/esm/utils/identityCacheSweep.js +92 -0
  23. package/dist/types/.tsbuildinfo +1 -1
  24. package/dist/types/index.d.ts +2 -2
  25. package/dist/types/mixins/OxyServices.accounts.d.ts +39 -7
  26. package/dist/types/mixins/OxyServices.user.d.ts +9 -7
  27. package/dist/types/models/interfaces.d.ts +11 -3
  28. package/dist/types/server/index.d.ts +4 -2
  29. package/dist/types/server/userInvalidation.d.ts +5 -24
  30. package/dist/types/utils/identityCacheSweep.d.ts +80 -0
  31. package/package.json +2 -2
  32. package/src/i18n/locales/en-US.json +48 -5
  33. package/src/i18n/locales/es-ES.json +48 -5
  34. package/src/index.ts +8 -2
  35. package/src/mixins/OxyServices.accounts.ts +58 -7
  36. package/src/mixins/OxyServices.user.ts +14 -20
  37. package/src/mixins/__tests__/identityWriteCacheInvalidation.test.ts +370 -0
  38. package/src/models/interfaces.ts +11 -3
  39. package/src/server/__tests__/userInvalidation.test.ts +3 -20
  40. package/src/server/index.ts +5 -2
  41. package/src/server/userInvalidation.ts +8 -36
  42. package/src/utils/__tests__/identityCacheSweep.test.ts +151 -0
  43. package/src/utils/identityCacheSweep.ts +104 -0
@@ -1748,11 +1748,53 @@
1748
1748
  "description": "A programmatic account with service credentials"
1749
1749
  }
1750
1750
  },
1751
- "organizationCategory": {
1751
+ "accountCategory": {
1752
+ "news": "News",
1753
+ "politics": "Politics & policy",
1754
+ "business": "Business",
1755
+ "startup": "Startups & entrepreneurship",
1756
+ "finance": "Finance & investing",
1757
+ "crypto": "Crypto & web3",
1758
+ "marketplace": "Marketplace & classifieds",
1759
+ "retail": "Retail & ecommerce",
1760
+ "real_estate": "Real estate",
1752
1761
  "agency": "Real estate agency",
1762
+ "landlord": "Landlord & property management",
1753
1763
  "cooperative": "Housing cooperative",
1754
- "landlord": "Landlord / property manager",
1755
- "other": "Other organization"
1764
+ "architecture": "Architecture & construction",
1765
+ "technology": "Technology",
1766
+ "software": "Software & development",
1767
+ "ai": "AI & machine learning",
1768
+ "security": "Security & privacy",
1769
+ "automation": "Automation & tools",
1770
+ "science": "Science & research",
1771
+ "education": "Education & training",
1772
+ "books": "Books & writing",
1773
+ "health": "Health & medicine",
1774
+ "fitness": "Fitness & wellbeing",
1775
+ "sports": "Sports",
1776
+ "gaming": "Gaming & esports",
1777
+ "music": "Music",
1778
+ "film": "Film & TV",
1779
+ "podcast": "Podcasts & audio",
1780
+ "art": "Art & design",
1781
+ "photography": "Photography",
1782
+ "comedy": "Comedy",
1783
+ "food": "Food & drink",
1784
+ "travel": "Travel & places",
1785
+ "fashion": "Fashion & beauty",
1786
+ "home_garden": "Home & garden",
1787
+ "diy": "DIY & making",
1788
+ "automotive": "Cars & motoring",
1789
+ "animals": "Animals & pets",
1790
+ "family": "Family & parenting",
1791
+ "nonprofit": "Non-profit & charity",
1792
+ "government": "Government & public sector",
1793
+ "community": "Local community",
1794
+ "activism": "Activism & advocacy",
1795
+ "environment": "Environment & sustainability",
1796
+ "religion": "Religion & spirituality",
1797
+ "other": "Other"
1756
1798
  },
1757
1799
  "create": {
1758
1800
  "title": "Create account",
@@ -1772,8 +1814,9 @@
1772
1814
  "invalidChars": "Only letters, numbers, hyphens, and underscores",
1773
1815
  "checkFailed": "Could not check availability"
1774
1816
  },
1775
- "organizationCategory": {
1776
- "label": "Organization type"
1817
+ "accountCategory": {
1818
+ "label": "Categories",
1819
+ "hint": "Pick up to {{max}}. The first one is your main category."
1777
1820
  },
1778
1821
  "toasts": {
1779
1822
  "success": "Account created",
@@ -1748,11 +1748,53 @@
1748
1748
  "description": "Una cuenta programática con credenciales de servicio"
1749
1749
  }
1750
1750
  },
1751
- "organizationCategory": {
1751
+ "accountCategory": {
1752
+ "news": "Noticias",
1753
+ "politics": "Política",
1754
+ "business": "Negocios",
1755
+ "startup": "Startups y emprendimiento",
1756
+ "finance": "Finanzas e inversión",
1757
+ "crypto": "Cripto y web3",
1758
+ "marketplace": "Marketplace y anuncios",
1759
+ "retail": "Comercio y ecommerce",
1760
+ "real_estate": "Inmobiliaria",
1752
1761
  "agency": "Agencia inmobiliaria",
1762
+ "landlord": "Casero y gestión de fincas",
1753
1763
  "cooperative": "Cooperativa de vivienda",
1754
- "landlord": "Propietario / administrador de fincas",
1755
- "other": "Otra organización"
1764
+ "architecture": "Arquitectura y construcción",
1765
+ "technology": "Tecnología",
1766
+ "software": "Software y desarrollo",
1767
+ "ai": "IA y aprendizaje automático",
1768
+ "security": "Seguridad y privacidad",
1769
+ "automation": "Automatización y herramientas",
1770
+ "science": "Ciencia e investigación",
1771
+ "education": "Educación y formación",
1772
+ "books": "Libros y escritura",
1773
+ "health": "Salud y medicina",
1774
+ "fitness": "Deporte y bienestar",
1775
+ "sports": "Deportes",
1776
+ "gaming": "Videojuegos y esports",
1777
+ "music": "Música",
1778
+ "film": "Cine y TV",
1779
+ "podcast": "Pódcast y audio",
1780
+ "art": "Arte y diseño",
1781
+ "photography": "Fotografía",
1782
+ "comedy": "Comedia",
1783
+ "food": "Comida y bebida",
1784
+ "travel": "Viajes y lugares",
1785
+ "fashion": "Moda y belleza",
1786
+ "home_garden": "Hogar y jardín",
1787
+ "diy": "Bricolaje y manualidades",
1788
+ "automotive": "Coches y motor",
1789
+ "animals": "Animales y mascotas",
1790
+ "family": "Familia y crianza",
1791
+ "nonprofit": "ONG y benéficas",
1792
+ "government": "Gobierno y sector público",
1793
+ "community": "Comunidad local",
1794
+ "activism": "Activismo y defensa",
1795
+ "environment": "Medio ambiente y sostenibilidad",
1796
+ "religion": "Religión y espiritualidad",
1797
+ "other": "Otra"
1756
1798
  },
1757
1799
  "create": {
1758
1800
  "title": "Crear cuenta",
@@ -1772,8 +1814,9 @@
1772
1814
  "invalidChars": "Solo letras, números, guiones y guiones bajos",
1773
1815
  "checkFailed": "No se pudo comprobar la disponibilidad"
1774
1816
  },
1775
- "organizationCategory": {
1776
- "label": "Tipo de organización"
1817
+ "accountCategory": {
1818
+ "label": "Categorías",
1819
+ "hint": "Elige hasta {{max}}. La primera es tu categoría principal."
1777
1820
  },
1778
1821
  "toasts": {
1779
1822
  "success": "Cuenta creada",
@@ -1748,11 +1748,53 @@
1748
1748
  "description": "A programmatic account with service credentials"
1749
1749
  }
1750
1750
  },
1751
- "organizationCategory": {
1751
+ "accountCategory": {
1752
+ "news": "News",
1753
+ "politics": "Politics & policy",
1754
+ "business": "Business",
1755
+ "startup": "Startups & entrepreneurship",
1756
+ "finance": "Finance & investing",
1757
+ "crypto": "Crypto & web3",
1758
+ "marketplace": "Marketplace & classifieds",
1759
+ "retail": "Retail & ecommerce",
1760
+ "real_estate": "Real estate",
1752
1761
  "agency": "Real estate agency",
1762
+ "landlord": "Landlord & property management",
1753
1763
  "cooperative": "Housing cooperative",
1754
- "landlord": "Landlord / property manager",
1755
- "other": "Other organization"
1764
+ "architecture": "Architecture & construction",
1765
+ "technology": "Technology",
1766
+ "software": "Software & development",
1767
+ "ai": "AI & machine learning",
1768
+ "security": "Security & privacy",
1769
+ "automation": "Automation & tools",
1770
+ "science": "Science & research",
1771
+ "education": "Education & training",
1772
+ "books": "Books & writing",
1773
+ "health": "Health & medicine",
1774
+ "fitness": "Fitness & wellbeing",
1775
+ "sports": "Sports",
1776
+ "gaming": "Gaming & esports",
1777
+ "music": "Music",
1778
+ "film": "Film & TV",
1779
+ "podcast": "Podcasts & audio",
1780
+ "art": "Art & design",
1781
+ "photography": "Photography",
1782
+ "comedy": "Comedy",
1783
+ "food": "Food & drink",
1784
+ "travel": "Travel & places",
1785
+ "fashion": "Fashion & beauty",
1786
+ "home_garden": "Home & garden",
1787
+ "diy": "DIY & making",
1788
+ "automotive": "Cars & motoring",
1789
+ "animals": "Animals & pets",
1790
+ "family": "Family & parenting",
1791
+ "nonprofit": "Non-profit & charity",
1792
+ "government": "Government & public sector",
1793
+ "community": "Local community",
1794
+ "activism": "Activism & advocacy",
1795
+ "environment": "Environment & sustainability",
1796
+ "religion": "Religion & spirituality",
1797
+ "other": "Other"
1756
1798
  },
1757
1799
  "create": {
1758
1800
  "title": "Create account",
@@ -1772,8 +1814,9 @@
1772
1814
  "invalidChars": "Only letters, numbers, hyphens, and underscores",
1773
1815
  "checkFailed": "Could not check availability"
1774
1816
  },
1775
- "organizationCategory": {
1776
- "label": "Organization type"
1817
+ "accountCategory": {
1818
+ "label": "Categories",
1819
+ "hint": "Pick up to {{max}}. The first one is your main category."
1777
1820
  },
1778
1821
  "toasts": {
1779
1822
  "success": "Account created",
@@ -1748,11 +1748,53 @@
1748
1748
  "description": "Una cuenta programática con credenciales de servicio"
1749
1749
  }
1750
1750
  },
1751
- "organizationCategory": {
1751
+ "accountCategory": {
1752
+ "news": "Noticias",
1753
+ "politics": "Política",
1754
+ "business": "Negocios",
1755
+ "startup": "Startups y emprendimiento",
1756
+ "finance": "Finanzas e inversión",
1757
+ "crypto": "Cripto y web3",
1758
+ "marketplace": "Marketplace y anuncios",
1759
+ "retail": "Comercio y ecommerce",
1760
+ "real_estate": "Inmobiliaria",
1752
1761
  "agency": "Agencia inmobiliaria",
1762
+ "landlord": "Casero y gestión de fincas",
1753
1763
  "cooperative": "Cooperativa de vivienda",
1754
- "landlord": "Propietario / administrador de fincas",
1755
- "other": "Otra organización"
1764
+ "architecture": "Arquitectura y construcción",
1765
+ "technology": "Tecnología",
1766
+ "software": "Software y desarrollo",
1767
+ "ai": "IA y aprendizaje automático",
1768
+ "security": "Seguridad y privacidad",
1769
+ "automation": "Automatización y herramientas",
1770
+ "science": "Ciencia e investigación",
1771
+ "education": "Educación y formación",
1772
+ "books": "Libros y escritura",
1773
+ "health": "Salud y medicina",
1774
+ "fitness": "Deporte y bienestar",
1775
+ "sports": "Deportes",
1776
+ "gaming": "Videojuegos y esports",
1777
+ "music": "Música",
1778
+ "film": "Cine y TV",
1779
+ "podcast": "Pódcast y audio",
1780
+ "art": "Arte y diseño",
1781
+ "photography": "Fotografía",
1782
+ "comedy": "Comedia",
1783
+ "food": "Comida y bebida",
1784
+ "travel": "Viajes y lugares",
1785
+ "fashion": "Moda y belleza",
1786
+ "home_garden": "Hogar y jardín",
1787
+ "diy": "Bricolaje y manualidades",
1788
+ "automotive": "Coches y motor",
1789
+ "animals": "Animales y mascotas",
1790
+ "family": "Familia y crianza",
1791
+ "nonprofit": "ONG y benéficas",
1792
+ "government": "Gobierno y sector público",
1793
+ "community": "Comunidad local",
1794
+ "activism": "Activismo y defensa",
1795
+ "environment": "Medio ambiente y sostenibilidad",
1796
+ "religion": "Religión y espiritualidad",
1797
+ "other": "Otra"
1756
1798
  },
1757
1799
  "create": {
1758
1800
  "title": "Crear cuenta",
@@ -1772,8 +1814,9 @@
1772
1814
  "invalidChars": "Solo letras, números, guiones y guiones bajos",
1773
1815
  "checkFailed": "No se pudo comprobar la disponibilidad"
1774
1816
  },
1775
- "organizationCategory": {
1776
- "label": "Tipo de organización"
1817
+ "accountCategory": {
1818
+ "label": "Categorías",
1819
+ "hint": "Elige hasta {{max}}. La primera es tu categoría principal."
1777
1820
  },
1778
1821
  "toasts": {
1779
1822
  "success": "Cuenta creada",
package/dist/cjs/index.js CHANGED
@@ -18,11 +18,11 @@
18
18
  * If a symbol does not appear here, it is NOT part of the public API.
19
19
  */
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.SECURITY_EVENT_SEVERITY_MAP = exports.DeviceManager = exports.deriveSharedSecret = exports.AEAD_NONCE_LENGTH = exports.AEAD_KEY_LENGTH = exports.decryptAead = exports.encryptAead = exports.hkdfSha256 = exports.RecoveryPhraseService = exports.SignatureService = exports.updateIdentityMarker = exports.readIdentityMarker = exports.IdentityUnavailableError = exports.IdentityPersistError = exports.IdentityAlreadyExistsError = exports.KeyManager = exports.sessionsArraysEqual = exports.normalizeAndSortSessions = exports.mergeSessions = exports.authenticatedApiCall = exports.withAuthErrorHandling = exports.isAuthenticationError = exports.ensureValidToken = exports.AuthenticationFailedError = exports.SessionSyncRequiredError = exports.verifyPublicCardAttestation = exports.parseAttestPayload = exports.parseIdPayload = exports.buildUserDid = exports.ORGANIZATION_CATEGORIES = exports.normalizeProfileLinks = exports.getNormalizedUserHandle = exports.getCanonicalUserHandle = exports.normalizeUserIdentityOrNull = exports.normalizeUserIdentity = exports.getNormalizedUserId = exports.OxyAppDataIdentifierError = exports.commonsDeliveryPlatform = exports.pushTargetsFromDelivery = exports.selectCommonsDelivery = exports.parseCommonsApprovalExpiresAt = exports.getCommonsApprovalBlockingReason = exports.ServiceCredentialMismatchError = exports.oxyClient = exports.OXY_CLOUD_URL = exports.ServiceAssetMetadataError = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.AssetUrlResolutionError = exports.OxyServices = void 0;
22
- exports.delay = exports.shouldAllowRequest = exports.recordSuccess = exports.recordFailure = exports.calculateBackoffInterval = exports.createCircuitBreakerState = exports.DEFAULT_CIRCUIT_BREAKER_CONFIG = exports.isRetryableError = exports.isNetworkError = exports.isServerError = exports.isRateLimitError = exports.isNotFoundError = exports.isForbiddenError = exports.isUnauthorizedError = exports.isAlreadyRegisteredError = exports.getErrorMessage = exports.getErrorStatus = exports.HttpStatus = exports.getSystemColorScheme = exports.systemPrefersDarkMode = exports.getOppositeTheme = exports.normalizeColorScheme = exports.normalizeTheme = exports.getContrastTextColor = exports.isLightColor = exports.withOpacity = exports.rgbToHex = exports.hexToRgb = exports.lightenColor = exports.darkenColor = exports.isWebBrowser = exports.isAndroid = exports.isIOS = exports.isNative = exports.isWeb = exports.setPlatformOS = exports.getPlatformOS = exports.getPrimaryLanguage = exports.getUserLanguages = exports.isRTLLocale = exports.getNativeLanguageName = exports.getLanguageName = exports.getLanguageMetadata = exports.isSupportedLocale = exports.normalizeLocale = exports.getBaseLanguage = exports.FALLBACK_LOCALE = exports.SUPPORTED_LANGUAGES = exports.TopicSource = exports.TopicType = void 0;
23
- exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = exports.resetLoggerConfig = exports.getLoggerConfig = exports.configureLogger = exports.createLogger = exports.logger = exports.normalizeMultilineText = exports.normalizeInlineText = exports.validateAndSanitizeUserInput = exports.isValidObjectId = exports.sanitizeHTML = exports.sanitizeString = exports.isValidFileType = exports.isValidFileSize = exports.isValidDate = exports.isValidURL = exports.isValidUUID = exports.isValidObject = exports.isValidArray = exports.isRequiredBoolean = exports.isRequiredNumber = exports.isRequiredString = exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE = exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.isValidDisplayName = exports.isValidPassword = exports.isValidUsername = exports.isValidEmail = exports.DISPLAY_NAME_INVALID_MESSAGE = exports.MAX_DISPLAY_NAME_LENGTH = exports.PASSWORD_REGEX = exports.USERNAME_REGEX = exports.EMAIL_REGEX = exports.retryAsync = exports.validateRequiredFields = exports.handleHttpError = exports.createApiError = exports.ErrorCodes = exports.safeJsonParse = exports.buildPaginationParams = exports.buildUrl = exports.buildSearchParams = exports.buildQueryParams = exports.translate = exports.withRetry = void 0;
24
- exports.resolveIdentityPin = exports.IDENTITY_PIN_STORAGE_KEY = exports.identityPinMatches = exports.createMemoryIdentityPinStore = exports.createNativeIdentityPinStore = exports.createWebIdentityPinStore = exports.AUTH_STATE_STORAGE_KEY = exports.createMemoryAuthStateStore = exports.createNativeAuthStateStore = exports.createWebAuthStateStore = exports.createAccountDialogController = exports.AccountDialogController = exports.switchableAccountIds = exports.projectSwitchableAccounts = exports.accountIdsOf = exports.activeUserOf = exports.activeSessionIdOf = exports.deviceStateToClientSessions = exports.createSessionClient = exports.createSessionClientHost = exports.SessionClient = exports.isAllowedDeviceJoinOrigin = exports.isOfficialWebOrigin = exports.isLoopbackOrigin = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.runColdBoot = exports.isOxyRpOrigin = exports.CENTRAL_IDP_APEX = exports.registrableApex = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = void 0;
25
- exports.packageInfo = exports.runSessionColdBoot = exports.TOKEN_REFRESH_LEAD_MS = exports.startTokenRefreshScheduler = exports.installAuthRefreshHandler = exports.createAuthRefreshHandler = exports.refreshDeviceSecretArm = exports.refreshPersistedSession = exports.AccountNotOnDeviceError = exports.establishIdentitySession = void 0;
21
+ exports.AEAD_KEY_LENGTH = exports.decryptAead = exports.encryptAead = exports.hkdfSha256 = exports.RecoveryPhraseService = exports.SignatureService = exports.updateIdentityMarker = exports.readIdentityMarker = exports.IdentityUnavailableError = exports.IdentityPersistError = exports.IdentityAlreadyExistsError = exports.KeyManager = exports.sessionsArraysEqual = exports.normalizeAndSortSessions = exports.mergeSessions = exports.authenticatedApiCall = exports.withAuthErrorHandling = exports.isAuthenticationError = exports.ensureValidToken = exports.AuthenticationFailedError = exports.SessionSyncRequiredError = exports.verifyPublicCardAttestation = exports.parseAttestPayload = exports.parseIdPayload = exports.buildUserDid = exports.kindAcceptsAccountCategories = exports.isSelectableAccountCategoryId = exports.SELECTABLE_ACCOUNT_CATEGORY_IDS = exports.MAX_ACCOUNT_CATEGORIES = exports.ACCOUNT_CATEGORY_IDS = exports.normalizeProfileLinks = exports.getNormalizedUserHandle = exports.getCanonicalUserHandle = exports.normalizeUserIdentityOrNull = exports.normalizeUserIdentity = exports.getNormalizedUserId = exports.OxyAppDataIdentifierError = exports.commonsDeliveryPlatform = exports.pushTargetsFromDelivery = exports.selectCommonsDelivery = exports.parseCommonsApprovalExpiresAt = exports.getCommonsApprovalBlockingReason = exports.ServiceCredentialMismatchError = exports.oxyClient = exports.OXY_CLOUD_URL = exports.ServiceAssetMetadataError = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.AssetUrlResolutionError = exports.OxyServices = void 0;
22
+ exports.calculateBackoffInterval = exports.createCircuitBreakerState = exports.DEFAULT_CIRCUIT_BREAKER_CONFIG = exports.isRetryableError = exports.isNetworkError = exports.isServerError = exports.isRateLimitError = exports.isNotFoundError = exports.isForbiddenError = exports.isUnauthorizedError = exports.isAlreadyRegisteredError = exports.getErrorMessage = exports.getErrorStatus = exports.HttpStatus = exports.getSystemColorScheme = exports.systemPrefersDarkMode = exports.getOppositeTheme = exports.normalizeColorScheme = exports.normalizeTheme = exports.getContrastTextColor = exports.isLightColor = exports.withOpacity = exports.rgbToHex = exports.hexToRgb = exports.lightenColor = exports.darkenColor = exports.isWebBrowser = exports.isAndroid = exports.isIOS = exports.isNative = exports.isWeb = exports.setPlatformOS = exports.getPlatformOS = exports.getPrimaryLanguage = exports.getUserLanguages = exports.isRTLLocale = exports.getNativeLanguageName = exports.getLanguageName = exports.getLanguageMetadata = exports.isSupportedLocale = exports.normalizeLocale = exports.getBaseLanguage = exports.FALLBACK_LOCALE = exports.SUPPORTED_LANGUAGES = exports.TopicSource = exports.TopicType = exports.SECURITY_EVENT_SEVERITY_MAP = exports.DeviceManager = exports.deriveSharedSecret = exports.AEAD_NONCE_LENGTH = void 0;
23
+ exports.resetLoggerConfig = exports.getLoggerConfig = exports.configureLogger = exports.createLogger = exports.logger = exports.normalizeMultilineText = exports.normalizeInlineText = exports.validateAndSanitizeUserInput = exports.isValidObjectId = exports.sanitizeHTML = exports.sanitizeString = exports.isValidFileType = exports.isValidFileSize = exports.isValidDate = exports.isValidURL = exports.isValidUUID = exports.isValidObject = exports.isValidArray = exports.isRequiredBoolean = exports.isRequiredNumber = exports.isRequiredString = exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE = exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.isValidDisplayName = exports.isValidPassword = exports.isValidUsername = exports.isValidEmail = exports.DISPLAY_NAME_INVALID_MESSAGE = exports.MAX_DISPLAY_NAME_LENGTH = exports.PASSWORD_REGEX = exports.USERNAME_REGEX = exports.EMAIL_REGEX = exports.retryAsync = exports.validateRequiredFields = exports.handleHttpError = exports.createApiError = exports.ErrorCodes = exports.safeJsonParse = exports.buildPaginationParams = exports.buildUrl = exports.buildSearchParams = exports.buildQueryParams = exports.translate = exports.withRetry = exports.delay = exports.shouldAllowRequest = exports.recordSuccess = exports.recordFailure = void 0;
24
+ exports.createNativeIdentityPinStore = exports.createWebIdentityPinStore = exports.AUTH_STATE_STORAGE_KEY = exports.createMemoryAuthStateStore = exports.createNativeAuthStateStore = exports.createWebAuthStateStore = exports.createAccountDialogController = exports.AccountDialogController = exports.switchableAccountIds = exports.projectSwitchableAccounts = exports.accountIdsOf = exports.activeUserOf = exports.activeSessionIdOf = exports.deviceStateToClientSessions = exports.createSessionClient = exports.createSessionClientHost = exports.SessionClient = exports.isAllowedDeviceJoinOrigin = exports.isOfficialWebOrigin = exports.isLoopbackOrigin = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.runColdBoot = exports.isOxyRpOrigin = exports.CENTRAL_IDP_APEX = exports.registrableApex = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = void 0;
25
+ exports.packageInfo = exports.runSessionColdBoot = exports.TOKEN_REFRESH_LEAD_MS = exports.startTokenRefreshScheduler = exports.installAuthRefreshHandler = exports.createAuthRefreshHandler = exports.refreshDeviceSecretArm = exports.refreshPersistedSession = exports.AccountNotOnDeviceError = exports.establishIdentitySession = exports.resolveIdentityPin = exports.IDENTITY_PIN_STORAGE_KEY = exports.identityPinMatches = exports.createMemoryIdentityPinStore = void 0;
26
26
  // Ensure crypto polyfills are loaded before anything else
27
27
  require("./crypto/polyfill");
28
28
  // ---------------------------------------------------------------------------
@@ -66,7 +66,11 @@ Object.defineProperty(exports, "getNormalizedUserHandle", { enumerable: true, ge
66
66
  var profileLinks_1 = require("./utils/profileLinks");
67
67
  Object.defineProperty(exports, "normalizeProfileLinks", { enumerable: true, get: function () { return profileLinks_1.normalizeProfileLinks; } });
68
68
  var OxyServices_accounts_1 = require("./mixins/OxyServices.accounts");
69
- Object.defineProperty(exports, "ORGANIZATION_CATEGORIES", { enumerable: true, get: function () { return OxyServices_accounts_1.ORGANIZATION_CATEGORIES; } });
69
+ Object.defineProperty(exports, "ACCOUNT_CATEGORY_IDS", { enumerable: true, get: function () { return OxyServices_accounts_1.ACCOUNT_CATEGORY_IDS; } });
70
+ Object.defineProperty(exports, "MAX_ACCOUNT_CATEGORIES", { enumerable: true, get: function () { return OxyServices_accounts_1.MAX_ACCOUNT_CATEGORIES; } });
71
+ Object.defineProperty(exports, "SELECTABLE_ACCOUNT_CATEGORY_IDS", { enumerable: true, get: function () { return OxyServices_accounts_1.SELECTABLE_ACCOUNT_CATEGORY_IDS; } });
72
+ Object.defineProperty(exports, "isSelectableAccountCategoryId", { enumerable: true, get: function () { return OxyServices_accounts_1.isSelectableAccountCategoryId; } });
73
+ Object.defineProperty(exports, "kindAcceptsAccountCategories", { enumerable: true, get: function () { return OxyServices_accounts_1.kindAcceptsAccountCategories; } });
70
74
  // ---------------------------------------------------------------------------
71
75
  // Reputation (Oxy Trust: ledger, balances, disputes, rules, influence).
72
76
  // The whole type family — the closed value sets, the two balance views and the
@@ -1,13 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isActAsEligibleKind = exports.ORGANIZATION_CATEGORIES = exports.ACCOUNT_KINDS = void 0;
3
+ exports.kindAcceptsAccountCategories = exports.isSelectableAccountCategoryId = exports.isActAsEligibleKind = exports.SELECTABLE_ACCOUNT_CATEGORY_IDS = exports.MAX_ACCOUNT_CATEGORIES = exports.ACCOUNT_KINDS = exports.ACCOUNT_CATEGORY_IDS = void 0;
4
4
  exports.OxyServicesAccountsMixin = OxyServicesAccountsMixin;
5
5
  const userIdentity_1 = require("../utils/userIdentity");
6
+ const identityCacheSweep_1 = require("../utils/identityCacheSweep");
6
7
  const mixinHelpers_1 = require("./mixinHelpers");
7
8
  var contracts_1 = require("@oxyhq/contracts");
9
+ Object.defineProperty(exports, "ACCOUNT_CATEGORY_IDS", { enumerable: true, get: function () { return contracts_1.ACCOUNT_CATEGORY_IDS; } });
8
10
  Object.defineProperty(exports, "ACCOUNT_KINDS", { enumerable: true, get: function () { return contracts_1.ACCOUNT_KINDS; } });
9
- Object.defineProperty(exports, "ORGANIZATION_CATEGORIES", { enumerable: true, get: function () { return contracts_1.ORGANIZATION_CATEGORIES; } });
11
+ Object.defineProperty(exports, "MAX_ACCOUNT_CATEGORIES", { enumerable: true, get: function () { return contracts_1.MAX_ACCOUNT_CATEGORIES; } });
12
+ Object.defineProperty(exports, "SELECTABLE_ACCOUNT_CATEGORY_IDS", { enumerable: true, get: function () { return contracts_1.SELECTABLE_ACCOUNT_CATEGORY_IDS; } });
10
13
  Object.defineProperty(exports, "isActAsEligibleKind", { enumerable: true, get: function () { return contracts_1.isActAsEligibleKind; } });
14
+ Object.defineProperty(exports, "isSelectableAccountCategoryId", { enumerable: true, get: function () { return contracts_1.isSelectableAccountCategoryId; } });
15
+ Object.defineProperty(exports, "kindAcceptsAccountCategories", { enumerable: true, get: function () { return contracts_1.kindAcceptsAccountCategories; } });
11
16
  function OxyServicesAccountsMixin(Base) {
12
17
  return class extends Base {
13
18
  constructor(...args) {
@@ -165,6 +170,18 @@ function OxyServicesAccountsMixin(Base) {
165
170
  /**
166
171
  * Update an account's mutable profile fields. Tree placement changes
167
172
  * (reparenting) go through the dedicated move endpoint, not here.
173
+ *
174
+ * An account IS a user, so this write changes identity — and a profile
175
+ * screen never reads `/accounts/<id>`. It reads `GET /users/<id>` and
176
+ * `GET /profiles/username/<handle>`, both cached for 5 minutes in the
177
+ * CALLER'S OWN process, so busting only the account-graph keys left every
178
+ * profile surface serving the pre-edit avatar and name for the full TTL
179
+ * with a perfectly healthy server (the cross-service `oxy:user:invalidate`
180
+ * signal does not help: it evicts BACKEND caches, and cannot reach a cache
181
+ * living in a browser tab). {@link evictOxyIdentityCache} owns that key
182
+ * list — see its docs for why the handle-keyed entries are prefix-swept
183
+ * (a RENAME leaves the old handle's entry unreachable by any targeted key).
184
+ *
168
185
  * @param accountId - The account's Mongo `_id`.
169
186
  * @param data - Subset of updatable profile fields.
170
187
  */
@@ -175,6 +192,14 @@ function OxyServicesAccountsMixin(Base) {
175
192
  // data) so neither serves the pre-update snapshot.
176
193
  this.clearCacheEntry(`GET:/accounts/${encodeURIComponent(accountId)}`);
177
194
  this._invalidateAccountLists();
195
+ // The parent's children list embeds this account's profile and is keyed
196
+ // by the PARENT id, so it is reachable only from the response node.
197
+ const parentAccountId = res.account?.parentAccountId;
198
+ if (parentAccountId) {
199
+ this.clearCacheEntry(`GET:/accounts/${encodeURIComponent(parentAccountId)}/children`);
200
+ }
201
+ // Every identity read of this account, whichever key it lands under.
202
+ (0, identityCacheSweep_1.evictOxyIdentityCache)(this, accountId);
178
203
  return res.account;
179
204
  }
180
205
  catch (error) {
@@ -6,6 +6,7 @@ const apiUtils_1 = require("../utils/apiUtils");
6
6
  const keyManager_1 = require("../crypto/keyManager");
7
7
  const signatureService_1 = require("../crypto/signatureService");
8
8
  const userIdentity_1 = require("../utils/userIdentity");
9
+ const identityCacheSweep_1 = require("../utils/identityCacheSweep");
9
10
  const logger_1 = require("../logger");
10
11
  const errorUtils_1 = require("../utils/errorUtils");
11
12
  /**
@@ -347,28 +348,22 @@ function OxyServicesUserMixin(Base) {
347
348
  /**
348
349
  * Update user profile.
349
350
  *
350
- * Invalidates the SDK-side response cache for every endpoint that
351
- * returns the current user (`GET /users/me`, `GET /session/user/*`,
352
- * `GET /users/<id>`, `GET /profiles/username/*`) so the next read
353
- * doesn't return a stale snapshot. Without this, a follow-up
354
- * `getUserBySession` call inside the 2-minute cache window can return
355
- * the pre-update user most visibly during onboarding, where it
356
- * causes the username step to flicker back as if nothing was saved.
351
+ * Invalidates the SDK-side response cache for every endpoint that can
352
+ * return this user — the list is owned by {@link evictOxyIdentityCache}, so
353
+ * a new identity read is added in one place instead of to each writer
354
+ * separately (this method's own hand-written copy had already drifted from
355
+ * the server-side one, missing `GET /auth/lookup/*` and
356
+ * `GET /profiles/resolve`). Without the sweep a follow-up
357
+ * `getUserBySession` inside the cache window returns the pre-update user
358
+ * most visibly during onboarding, where the username step flickers back as
359
+ * if nothing was saved.
357
360
  *
358
361
  * TanStack Query handles offline queuing automatically.
359
362
  */
360
363
  async updateProfile(updates) {
361
364
  try {
362
365
  const result = (0, userIdentity_1.normalizeUserIdentity)(await this.makeRequest('PUT', '/users/me', updates, { cache: false }));
363
- // Bust every cached representation of the current user. We use a
364
- // prefix sweep rather than an enumeration because the SDK never
365
- // tracks the set of active session IDs centrally.
366
- this.clearCacheByPrefix('GET:/session/user/');
367
- this.clearCacheByPrefix('GET:/users/me');
368
- this.clearCacheByPrefix('GET:/profiles/username/');
369
- if (result?.id) {
370
- this.clearCacheEntry(`GET:/users/${result.id}`);
371
- }
366
+ (0, identityCacheSweep_1.evictOxyIdentityCache)(this, result?.id);
372
367
  return result;
373
368
  }
374
369
  catch (error) {
@@ -421,10 +416,9 @@ function OxyServicesUserMixin(Base) {
421
416
  const result = await this.makeRequest('PATCH', `/privacy/${id}/privacy`, settings, {
422
417
  cache: false,
423
418
  });
424
- this.clearCacheByPrefix('GET:/session/user/');
425
- this.clearCacheByPrefix('GET:/users/me');
426
- this.clearCacheByPrefix('GET:/profiles/username/');
427
- this.clearCacheEntry(`GET:/users/${id}`);
419
+ // Privacy settings ride the user DTO, so every identity read goes stale
420
+ // too — same key list as any other profile write.
421
+ (0, identityCacheSweep_1.evictOxyIdentityCache)(this, id);
428
422
  this.clearCacheEntry(`GET:/privacy/${id}/privacy`);
429
423
  return result;
430
424
  }
@@ -16,7 +16,7 @@
16
16
  * ```
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.isOfficialWebOrigin = exports.registrableApex = exports.publishOxyUserInvalidation = exports.evictOxyIdentityCache = exports.createOxyUserInvalidationHandler = exports.verifySecret = exports.OXY_CSP_BASELINE = exports.formatOxyCspPolicy = exports.createOxySecurityHeaders = exports.buildOxyPagesHeaders = exports.buildOxyCspDirectives = exports.createOxyCors = exports.UPSTREAM_HEADERS_TIMEOUT_MS = exports.MAX_URL_LENGTH = exports.MAX_REDIRECTS = exports.DEFAULT_USER_AGENT = exports.BLOCKED_HOSTNAMES = exports.ALLOWED_PROTOCOLS = exports.ALLOWED_PORTS = exports.UpstreamError = exports.SsrfRejection = exports.safeFetch = exports.isBlockedIp = exports.assertSafePublicUrl = exports.createOxyRateLimit = exports.OXY_SERVICE_ENVIRONMENTS = exports.requireOxyAuth = exports.isOxyAuthenticated = exports.getRequiredOxyUserId = exports.getOxyUserId = exports.createOxyAuthMiddleware = exports.createOptionalOxyAuth = void 0;
19
+ exports.isOfficialWebOrigin = exports.registrableApex = exports.OXY_IDENTITY_CACHE_PREFIXES = exports.oxyUserByIdCacheKey = exports.evictOxyIdentityCache = exports.publishOxyUserInvalidation = exports.createOxyUserInvalidationHandler = exports.verifySecret = exports.OXY_CSP_BASELINE = exports.formatOxyCspPolicy = exports.createOxySecurityHeaders = exports.buildOxyPagesHeaders = exports.buildOxyCspDirectives = exports.createOxyCors = exports.UPSTREAM_HEADERS_TIMEOUT_MS = exports.MAX_URL_LENGTH = exports.MAX_REDIRECTS = exports.DEFAULT_USER_AGENT = exports.BLOCKED_HOSTNAMES = exports.ALLOWED_PROTOCOLS = exports.ALLOWED_PORTS = exports.UpstreamError = exports.SsrfRejection = exports.safeFetch = exports.isBlockedIp = exports.assertSafePublicUrl = exports.createOxyRateLimit = exports.OXY_SERVICE_ENVIRONMENTS = exports.requireOxyAuth = exports.isOxyAuthenticated = exports.getRequiredOxyUserId = exports.getOxyUserId = exports.createOxyAuthMiddleware = exports.createOptionalOxyAuth = void 0;
20
20
  var auth_1 = require("./auth");
21
21
  Object.defineProperty(exports, "createOptionalOxyAuth", { enumerable: true, get: function () { return auth_1.createOptionalOxyAuth; } });
22
22
  Object.defineProperty(exports, "createOxyAuthMiddleware", { enumerable: true, get: function () { return auth_1.createOxyAuthMiddleware; } });
@@ -59,8 +59,14 @@ Object.defineProperty(exports, "verifySecret", { enumerable: true, get: function
59
59
  // changes, every consuming backend sweeps its caches instead of waiting out a TTL.
60
60
  var userInvalidation_1 = require("./userInvalidation");
61
61
  Object.defineProperty(exports, "createOxyUserInvalidationHandler", { enumerable: true, get: function () { return userInvalidation_1.createOxyUserInvalidationHandler; } });
62
- Object.defineProperty(exports, "evictOxyIdentityCache", { enumerable: true, get: function () { return userInvalidation_1.evictOxyIdentityCache; } });
63
62
  Object.defineProperty(exports, "publishOxyUserInvalidation", { enumerable: true, get: function () { return userInvalidation_1.publishOxyUserInvalidation; } });
63
+ // The identity-key enumeration itself is platform-neutral (`src/utils/`) so the
64
+ // client mixins and this Node-only subscriber sweep the SAME list — a second
65
+ // copy is what let `updateAccount` and `updateProfile` drift apart.
66
+ var identityCacheSweep_1 = require("../utils/identityCacheSweep");
67
+ Object.defineProperty(exports, "evictOxyIdentityCache", { enumerable: true, get: function () { return identityCacheSweep_1.evictOxyIdentityCache; } });
68
+ Object.defineProperty(exports, "oxyUserByIdCacheKey", { enumerable: true, get: function () { return identityCacheSweep_1.oxyUserByIdCacheKey; } });
69
+ Object.defineProperty(exports, "OXY_IDENTITY_CACHE_PREFIXES", { enumerable: true, get: function () { return identityCacheSweep_1.OXY_IDENTITY_CACHE_PREFIXES; } });
64
70
  // Registrable-apex (eTLD+1) derivation via the Public Suffix List — the SINGLE
65
71
  // SOURCE OF TRUTH shared with the IdP worker and the client FAPI auto-detect.
66
72
  // Pure host handling (no browser deps), so it is safe on the server subpath and
@@ -7,10 +7,10 @@
7
7
  * Every Oxy backend caches Oxy identity, and none of them find out when it
8
8
  * changes. The `OxyServices` GET response cache holds `GET /users/:id` and
9
9
  * `GET /profiles/username/:name` for five minutes; it is swept when THIS process
10
- * writes the profile (see the `clearCacheEntry` calls in the user mixin) and
11
- * never when somebody else does — which is the normal case, since profiles are
12
- * edited in Oxy's own apps. So an avatar or display-name change is invisible to
13
- * every consuming backend for up to five minutes, per process.
10
+ * writes the profile (the `evictOxyIdentityCache` calls in the user and accounts
11
+ * mixins) and never when somebody else does — which is the normal case, since
12
+ * profiles are edited in Oxy's own apps. So an avatar or display-name change is
13
+ * invisible to every consuming backend for up to five minutes, per process.
14
14
  *
15
15
  * oxy-api broadcasts {@link OXY_USER_INVALIDATION_CHANNEL} on the shared Valkey
16
16
  * when a user's identity changes. This module is the consumer half: it parses
@@ -54,8 +54,8 @@
54
54
  Object.defineProperty(exports, "__esModule", { value: true });
55
55
  exports.publishOxyUserInvalidation = publishOxyUserInvalidation;
56
56
  exports.createOxyUserInvalidationHandler = createOxyUserInvalidationHandler;
57
- exports.evictOxyIdentityCache = evictOxyIdentityCache;
58
57
  const contracts_1 = require("@oxyhq/contracts");
58
+ const identityCacheSweep_1 = require("../utils/identityCacheSweep");
59
59
  /**
60
60
  * Broadcast that an Oxy user's record changed.
61
61
  *
@@ -134,7 +134,7 @@ function createOxyUserInvalidationHandler(options = {}) {
134
134
  }
135
135
  if (oxy) {
136
136
  try {
137
- evictOxyIdentityCache(oxy, event.userId);
137
+ (0, identityCacheSweep_1.evictOxyIdentityCache)(oxy, event.userId);
138
138
  }
139
139
  catch (error) {
140
140
  // A cache sweep must never cost us the app-specific eviction below.
@@ -154,25 +154,3 @@ function createOxyUserInvalidationHandler(options = {}) {
154
154
  }
155
155
  };
156
156
  }
157
- /**
158
- * Sweep an `OxyServices` GET response cache of everything that could carry the
159
- * given user's identity.
160
- *
161
- * The by-id entry is exact. The by-username and resolve entries are keyed by
162
- * HANDLE, which cannot be derived from an id without the very lookup we are
163
- * invalidating, so those are swept by prefix — the same imprecision the SDK
164
- * already accepts when it sweeps its own cache after a local profile write, and
165
- * bounded by the fact that over-eviction costs a refetch and can never serve
166
- * wrong data.
167
- */
168
- function evictOxyIdentityCache(oxy, userId) {
169
- // Match the sweep the user mixin runs after a local profile write — session-
170
- // bound and /users/me entries are keyed without the user id, so they must be
171
- // prefix-swept on cross-service invalidation too.
172
- oxy.clearCacheByPrefix('GET:/session/user/');
173
- oxy.clearCacheByPrefix('GET:/users/me');
174
- oxy.clearCacheByPrefix('GET:/auth/lookup/');
175
- oxy.clearCacheEntry(`GET:/users/${userId}`);
176
- oxy.clearCacheByPrefix('GET:/profiles/username/');
177
- oxy.clearCacheByPrefix('GET:/profiles/resolve');
178
- }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ /**
3
+ * THE enumeration of `OxyServices` GET-cache keys that can carry a single
4
+ * account's identity, and the one sweep that clears them.
5
+ *
6
+ * WHY THIS IS ONE LIST
7
+ * --------------------
8
+ * An Oxy account is readable under SEVERAL cache keys, and a write that only
9
+ * busts the key it happens to know about leaves every other one serving the
10
+ * pre-write snapshot for up to its TTL — from the caller's OWN in-memory cache,
11
+ * with a perfectly healthy server. That failure has already shipped twice with
12
+ * two different sets of keys:
13
+ *
14
+ * - `updateAccount` busted `GET:/accounts/<id>` and the account lists, but a
15
+ * profile screen reads `GET:/profiles/username/<name>` and
16
+ * `GET:/users/<id>`, so a channel's new picture stayed invisible for the
17
+ * full 5-minute profile TTL.
18
+ * - `updateProfile` busted four of the six keys below, missing
19
+ * `GET:/auth/lookup/` (the login-flow avatar/display-name lookup) and
20
+ * `GET:/profiles/resolve` (handle resolution) — two independently-drifted
21
+ * copies of a list that has to agree.
22
+ *
23
+ * So the list lives here, once, and every writer calls
24
+ * {@link evictOxyIdentityCache}. Adding a new identity read means adding its key
25
+ * HERE and every writer inherits it.
26
+ *
27
+ * WHERE THE LINE IS DRAWN
28
+ * -----------------------
29
+ * These are the SINGLE-PROFILE reads — the account is the subject of the
30
+ * response and is addressable by id, handle, or session. Reads that merely
31
+ * CONTAIN an account among many (`GET:/profiles/search`,
32
+ * `GET:/users/<other>/followers`, `GET:/profiles/<other>/similar`) are
33
+ * deliberately NOT swept: an account cannot be located in them without the very
34
+ * lookup being invalidated, so sweeping them means sweeping the whole namespace
35
+ * on every identity change — a real cost on a backend consuming the
36
+ * cross-service invalidation signal, for a surface where a stale thumbnail
37
+ * expires on its own in ~2 minutes.
38
+ *
39
+ * WHY PREFIXES RATHER THAN EXACT KEYS
40
+ * -----------------------------------
41
+ * Only the by-id key can be built from a user id. The handle-keyed and
42
+ * session-keyed entries cannot — deriving a handle from an id needs the lookup
43
+ * we are invalidating, and the SDK never tracks active session ids centrally.
44
+ * Prefix sweeping is also what makes a USERNAME CHANGE correct: the entry under
45
+ * the OLD handle is unreachable by construction (nothing in the write response
46
+ * carries it), and a sweep targeted at the new handle alone would leave the old
47
+ * one serving the pre-rename profile until its TTL. Over-eviction costs a
48
+ * refetch; under-eviction serves wrong data.
49
+ *
50
+ * Platform-neutral by construction (no imports, no `OxyServices` reference) so
51
+ * the client mixins and the Node-only `@oxyhq/core/server` invalidation
52
+ * subscriber can share it without either pulling in the other.
53
+ */
54
+ Object.defineProperty(exports, "__esModule", { value: true });
55
+ exports.OXY_IDENTITY_CACHE_PREFIXES = void 0;
56
+ exports.oxyUserByIdCacheKey = oxyUserByIdCacheKey;
57
+ exports.evictOxyIdentityCache = evictOxyIdentityCache;
58
+ /**
59
+ * Cache-key PREFIXES under which an account's identity can be served, for the
60
+ * reads whose key cannot be derived from a user id. Swept wholesale.
61
+ */
62
+ exports.OXY_IDENTITY_CACHE_PREFIXES = [
63
+ // `getUserBySession` — keyed by session id, which the SDK never enumerates.
64
+ 'GET:/session/user/',
65
+ // `getCurrentUser` (and `GET:/users/me/graph`, harmlessly included).
66
+ 'GET:/users/me',
67
+ // `lookupUsername` — the pre-session login lookup; carries avatar + display name.
68
+ 'GET:/auth/lookup/',
69
+ // `getProfileByUsername` — keyed by handle, including the pre-rename handle.
70
+ 'GET:/profiles/username/',
71
+ // `resolveProfile` — keyed by fediverse handle in the query payload.
72
+ 'GET:/profiles/resolve',
73
+ ];
74
+ /**
75
+ * Build the exact cache key `getUserById` reads under. The only identity key
76
+ * derivable from a user id, so the only one that does not need a prefix sweep.
77
+ */
78
+ function oxyUserByIdCacheKey(userId) {
79
+ return `GET:/users/${userId}`;
80
+ }
81
+ /**
82
+ * Sweep an `OxyServices` GET response cache of everything that could carry the
83
+ * given account's identity.
84
+ *
85
+ * @param oxy - Anything exposing the SDK's two eviction methods.
86
+ * @param userId - The account whose by-id entry to drop. Optional: a caller
87
+ * that does not know the id still clears every handle-, session-
88
+ * and self-keyed entry, which is the majority of the surface.
89
+ */
90
+ function evictOxyIdentityCache(oxy, userId) {
91
+ for (const prefix of exports.OXY_IDENTITY_CACHE_PREFIXES) {
92
+ oxy.clearCacheByPrefix(prefix);
93
+ }
94
+ if (userId) {
95
+ oxy.clearCacheEntry(oxyUserByIdCacheKey(userId));
96
+ }
97
+ }