@oxyhq/core 9.2.4 → 10.1.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 (69) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/i18n/index.js +22 -2
  3. package/dist/cjs/i18n/locales/en-US.json +4 -1
  4. package/dist/cjs/i18n/locales/es-ES.json +4 -1
  5. package/dist/cjs/i18n/locales/locales/en-US.json +4 -1
  6. package/dist/cjs/i18n/locales/locales/es-ES.json +4 -1
  7. package/dist/cjs/index.js +16 -5
  8. package/dist/cjs/mixins/OxyServices.assets.js +10 -6
  9. package/dist/cjs/mixins/OxyServices.language.js +11 -10
  10. package/dist/cjs/mixins/OxyServices.privacy.js +6 -0
  11. package/dist/cjs/mixins/OxyServices.user.js +40 -0
  12. package/dist/cjs/server/safeFetch.js +3 -3
  13. package/dist/cjs/session/SessionClient.js +1 -1
  14. package/dist/cjs/shared/utils/colorUtils.js +9 -9
  15. package/dist/cjs/utils/languageUtils.js +195 -158
  16. package/dist/cjs/utils/platform.js +9 -2
  17. package/dist/cjs/utils/textNormalization.js +168 -0
  18. package/dist/esm/.tsbuildinfo +1 -1
  19. package/dist/esm/i18n/index.js +22 -2
  20. package/dist/esm/i18n/locales/en-US.json +4 -1
  21. package/dist/esm/i18n/locales/es-ES.json +4 -1
  22. package/dist/esm/i18n/locales/locales/en-US.json +4 -1
  23. package/dist/esm/i18n/locales/locales/es-ES.json +4 -1
  24. package/dist/esm/index.js +5 -1
  25. package/dist/esm/mixins/OxyServices.assets.js +10 -6
  26. package/dist/esm/mixins/OxyServices.language.js +12 -11
  27. package/dist/esm/mixins/OxyServices.privacy.js +6 -0
  28. package/dist/esm/mixins/OxyServices.user.js +40 -0
  29. package/dist/esm/server/safeFetch.js +3 -3
  30. package/dist/esm/session/SessionClient.js +1 -1
  31. package/dist/esm/shared/utils/colorUtils.js +9 -9
  32. package/dist/esm/utils/languageUtils.js +189 -156
  33. package/dist/esm/utils/platform.js +9 -2
  34. package/dist/esm/utils/textNormalization.js +164 -0
  35. package/dist/types/.tsbuildinfo +1 -1
  36. package/dist/types/index.d.ts +4 -3
  37. package/dist/types/mixins/OxyServices.language.d.ts +4 -4
  38. package/dist/types/mixins/OxyServices.user.d.ts +30 -0
  39. package/dist/types/models/interfaces.d.ts +14 -0
  40. package/dist/types/session/accountDialogController.d.ts +1 -1
  41. package/dist/types/utils/languageUtils.d.ts +86 -24
  42. package/dist/types/utils/textNormalization.d.ts +100 -0
  43. package/package.json +3 -3
  44. package/src/HttpService.ts +2 -2
  45. package/src/crypto/keyManager.ts +3 -3
  46. package/src/crypto/recoveryPhrase.ts +1 -1
  47. package/src/i18n/index.ts +21 -2
  48. package/src/i18n/locales/en-US.json +4 -1
  49. package/src/i18n/locales/es-ES.json +4 -1
  50. package/src/index.ts +16 -2
  51. package/src/mixins/OxyServices.assets.ts +15 -11
  52. package/src/mixins/OxyServices.language.ts +31 -17
  53. package/src/mixins/OxyServices.privacy.ts +6 -0
  54. package/src/mixins/OxyServices.security.ts +1 -1
  55. package/src/mixins/OxyServices.user.ts +57 -0
  56. package/src/models/interfaces.ts +14 -0
  57. package/src/server/safeFetch.ts +3 -3
  58. package/src/session/SessionClient.ts +1 -1
  59. package/src/session/accountDialogController.ts +1 -1
  60. package/src/shared/utils/colorUtils.ts +11 -11
  61. package/src/shared/utils/errorUtils.ts +1 -1
  62. package/src/utils/__tests__/languageUtils.test.ts +219 -0
  63. package/src/utils/__tests__/textNormalization.test.ts +196 -0
  64. package/src/utils/avatarUtils.ts +1 -1
  65. package/src/utils/languageUtils.ts +223 -162
  66. package/src/utils/platform.ts +21 -3
  67. package/src/utils/requestUtils.ts +3 -3
  68. package/src/utils/sessionUtils.ts +2 -2
  69. package/src/utils/textNormalization.ts +173 -0
@@ -16,6 +16,7 @@ const ja_JP_json_1 = __importDefault(require("./locales/ja-JP.json"));
16
16
  const ko_KR_json_1 = __importDefault(require("./locales/ko-KR.json"));
17
17
  const zh_CN_json_1 = __importDefault(require("./locales/zh-CN.json"));
18
18
  const ar_SA_json_1 = __importDefault(require("./locales/ar-SA.json"));
19
+ const languageUtils_1 = require("../utils/languageUtils");
19
20
  const DICTS = {
20
21
  'en': en_US_json_1.default,
21
22
  'en-US': en_US_json_1.default,
@@ -41,11 +42,30 @@ const DICTS = {
41
42
  'ar-SA': ar_SA_json_1.default,
42
43
  };
43
44
  const FALLBACK = 'en-US';
45
+ /**
46
+ * Resolve a locale tag to the key of the dictionary that should serve it.
47
+ *
48
+ * Account locales are full BCP-47 tags (e.g. `es-MX`, `pt-BR`, `fr-CA`), but a
49
+ * translation dictionary is shipped per base language. Resolution order:
50
+ * 1. Exact dictionary for the tag (e.g. `es-ES`).
51
+ * 2. Dictionary for the base subtag (e.g. `es-MX` → `es`).
52
+ * 3. The English fallback.
53
+ */
54
+ function resolveLang(locale) {
55
+ if (locale) {
56
+ if (DICTS[locale])
57
+ return locale;
58
+ const base = (0, languageUtils_1.getBaseLanguage)(locale);
59
+ if (DICTS[base])
60
+ return base;
61
+ }
62
+ return FALLBACK;
63
+ }
44
64
  function getNested(obj, path) {
45
65
  return path.split('.').reduce((acc, key) => (acc && acc[key] != null ? acc[key] : undefined), obj);
46
66
  }
47
67
  function translate(locale, key, vars) {
48
- const lang = locale && DICTS[locale] ? locale : FALLBACK;
68
+ const lang = resolveLang(locale);
49
69
  const dict = DICTS[lang] || DICTS[FALLBACK];
50
70
  let val = getNested(dict, key);
51
71
  // Per-key fallback to the English dictionary when a key is missing from the
@@ -65,6 +85,6 @@ function translate(locale, key, vars) {
65
85
  return val;
66
86
  }
67
87
  function hasKey(locale, key) {
68
- const lang = locale && DICTS[locale] ? locale : FALLBACK;
88
+ const lang = resolveLang(locale);
69
89
  return getNested(DICTS[lang], key) != null || getNested(DICTS[FALLBACK], key) != null;
70
90
  }
@@ -169,9 +169,12 @@
169
169
  },
170
170
  "language": {
171
171
  "title": "Language",
172
- "subtitle": "Choose your preferred language",
172
+ "subtitle": "Choose the languages you use. The first is your primary interface language.",
173
173
  "current": "Current Language",
174
+ "selected": "Your languages",
174
175
  "available": "Available Languages",
176
+ "primary": "Primary",
177
+ "remove": "Remove",
175
178
  "changed": "Language changed to {{lang}}",
176
179
  "saveFailed": "Failed to save language preference",
177
180
  "search": "Search languages"
@@ -123,9 +123,12 @@
123
123
  },
124
124
  "language": {
125
125
  "title": "Idioma",
126
- "subtitle": "Elige tu idioma preferido",
126
+ "subtitle": "Elige los idiomas que usas. El primero es tu idioma de interfaz principal.",
127
127
  "current": "Idioma actual",
128
+ "selected": "Tus idiomas",
128
129
  "available": "Idiomas disponibles",
130
+ "primary": "Principal",
131
+ "remove": "Quitar",
129
132
  "changed": "Idioma cambiado a {{lang}}",
130
133
  "saveFailed": "Error al guardar la preferencia de idioma",
131
134
  "search": "Buscar idiomas"
@@ -169,9 +169,12 @@
169
169
  },
170
170
  "language": {
171
171
  "title": "Language",
172
- "subtitle": "Choose your preferred language",
172
+ "subtitle": "Choose the languages you use. The first is your primary interface language.",
173
173
  "current": "Current Language",
174
+ "selected": "Your languages",
174
175
  "available": "Available Languages",
176
+ "primary": "Primary",
177
+ "remove": "Remove",
175
178
  "changed": "Language changed to {{lang}}",
176
179
  "saveFailed": "Failed to save language preference",
177
180
  "search": "Search languages"
@@ -123,9 +123,12 @@
123
123
  },
124
124
  "language": {
125
125
  "title": "Idioma",
126
- "subtitle": "Elige tu idioma preferido",
126
+ "subtitle": "Elige los idiomas que usas. El primero es tu idioma de interfaz principal.",
127
127
  "current": "Idioma actual",
128
+ "selected": "Tus idiomas",
128
129
  "available": "Idiomas disponibles",
130
+ "primary": "Principal",
131
+ "remove": "Quitar",
129
132
  "changed": "Idioma cambiado a {{lang}}",
130
133
  "saveFailed": "Error al guardar la preferencia de idioma",
131
134
  "search": "Buscar idiomas"
package/dist/cjs/index.js CHANGED
@@ -18,10 +18,10 @@
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.darkenColor = exports.isWebBrowser = exports.isAndroid = exports.isIOS = exports.isNative = exports.isWeb = exports.setPlatformOS = exports.getPlatformOS = exports.isRTLLocale = exports.normalizeLanguageCode = exports.getNativeLanguageName = exports.getLanguageName = exports.getLanguageMetadata = exports.SUPPORTED_LANGUAGES = exports.TopicSource = exports.TopicType = exports.SECURITY_EVENT_SEVERITY_MAP = exports.DeviceManager = exports.RecoveryPhraseService = exports.SignatureService = 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.ServiceCredentialMismatchError = exports.oxyClient = exports.OXY_CLOUD_URL = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.OxyServices = void 0;
22
- exports.isValidUsername = exports.isValidEmail = 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.translate = exports.createDebugLogger = exports.debugError = exports.debugWarn = exports.debugLog = exports.isDev = exports.withRetry = 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 = void 0;
23
- exports.buildIdpHubOrigin = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.normalizeOAuthRedirectUri = exports.OXY_CROSS_ORIGIN_RESTORE_ATTEMPTED_KEY = exports.OXY_SILENT_OAUTH_ATTEMPTED_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.CENTRAL_IDP_APEX = exports.registrableApex = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.logPerformance = exports.logPayment = exports.logDevice = exports.logUser = exports.logSession = exports.logApi = exports.logAuth = exports.LogLevel = exports.logger = 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.isValidDisplayName = exports.isValidPassword = void 0;
24
- exports.packageInfo = exports.runSessionColdBoot = exports.TOKEN_REFRESH_LEAD_MS = exports.startTokenRefreshScheduler = exports.installAuthRefreshHandler = exports.createAuthRefreshHandler = exports.refreshDeviceSecretArm = exports.refreshPersistedSession = 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.redeemHubTicketOnHub = exports.syncHubAfterSignIn = exports.parseHubSyncReturnUrl = exports.normalizeOfficialReturnOrigin = exports.isAllowedDeviceJoinOrigin = exports.isOfficialWebOrigin = exports.isIdpHubOrigin = exports.buildHubSyncUrl = void 0;
21
+ 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.RecoveryPhraseService = exports.SignatureService = 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.ServiceCredentialMismatchError = exports.oxyClient = exports.OXY_CLOUD_URL = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.OxyServices = void 0;
22
+ exports.retryAsync = exports.validateRequiredFields = exports.handleHttpError = exports.createApiError = exports.ErrorCodes = exports.safeJsonParse = exports.buildPaginationParams = exports.buildUrl = exports.buildSearchParams = exports.translate = exports.createDebugLogger = exports.debugError = exports.debugWarn = exports.debugLog = exports.isDev = exports.withRetry = 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 = void 0;
23
+ 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.CENTRAL_IDP_APEX = exports.registrableApex = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.logPerformance = exports.logPayment = exports.logDevice = exports.logUser = exports.logSession = exports.logApi = exports.logAuth = exports.LogLevel = 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.isValidDisplayName = exports.isValidPassword = exports.isValidUsername = exports.isValidEmail = exports.PASSWORD_REGEX = exports.USERNAME_REGEX = exports.EMAIL_REGEX = void 0;
24
+ exports.packageInfo = exports.runSessionColdBoot = exports.TOKEN_REFRESH_LEAD_MS = exports.startTokenRefreshScheduler = exports.installAuthRefreshHandler = exports.createAuthRefreshHandler = exports.refreshDeviceSecretArm = exports.refreshPersistedSession = 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.redeemHubTicketOnHub = exports.syncHubAfterSignIn = exports.parseHubSyncReturnUrl = exports.normalizeOfficialReturnOrigin = exports.isAllowedDeviceJoinOrigin = exports.isOfficialWebOrigin = exports.isIdpHubOrigin = exports.buildHubSyncUrl = exports.buildIdpHubOrigin = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.normalizeOAuthRedirectUri = exports.OXY_CROSS_ORIGIN_RESTORE_ATTEMPTED_KEY = exports.OXY_SILENT_OAUTH_ATTEMPTED_KEY = void 0;
25
25
  // Ensure crypto polyfills are loaded before anything else
26
26
  require("./crypto/polyfill");
27
27
  // ---------------------------------------------------------------------------
@@ -119,11 +119,16 @@ Object.defineProperty(exports, "TopicSource", { enumerable: true, get: function
119
119
  // ---------------------------------------------------------------------------
120
120
  var languageUtils_1 = require("./utils/languageUtils");
121
121
  Object.defineProperty(exports, "SUPPORTED_LANGUAGES", { enumerable: true, get: function () { return languageUtils_1.SUPPORTED_LANGUAGES; } });
122
+ Object.defineProperty(exports, "FALLBACK_LOCALE", { enumerable: true, get: function () { return languageUtils_1.FALLBACK_LOCALE; } });
123
+ Object.defineProperty(exports, "getBaseLanguage", { enumerable: true, get: function () { return languageUtils_1.getBaseLanguage; } });
124
+ Object.defineProperty(exports, "normalizeLocale", { enumerable: true, get: function () { return languageUtils_1.normalizeLocale; } });
125
+ Object.defineProperty(exports, "isSupportedLocale", { enumerable: true, get: function () { return languageUtils_1.isSupportedLocale; } });
122
126
  Object.defineProperty(exports, "getLanguageMetadata", { enumerable: true, get: function () { return languageUtils_1.getLanguageMetadata; } });
123
127
  Object.defineProperty(exports, "getLanguageName", { enumerable: true, get: function () { return languageUtils_1.getLanguageName; } });
124
128
  Object.defineProperty(exports, "getNativeLanguageName", { enumerable: true, get: function () { return languageUtils_1.getNativeLanguageName; } });
125
- Object.defineProperty(exports, "normalizeLanguageCode", { enumerable: true, get: function () { return languageUtils_1.normalizeLanguageCode; } });
126
129
  Object.defineProperty(exports, "isRTLLocale", { enumerable: true, get: function () { return languageUtils_1.isRTLLocale; } });
130
+ Object.defineProperty(exports, "getUserLanguages", { enumerable: true, get: function () { return languageUtils_1.getUserLanguages; } });
131
+ Object.defineProperty(exports, "getPrimaryLanguage", { enumerable: true, get: function () { return languageUtils_1.getPrimaryLanguage; } });
127
132
  // ---------------------------------------------------------------------------
128
133
  // Platform detection
129
134
  // ---------------------------------------------------------------------------
@@ -228,6 +233,12 @@ Object.defineProperty(exports, "sanitizeHTML", { enumerable: true, get: function
228
233
  Object.defineProperty(exports, "isValidObjectId", { enumerable: true, get: function () { return validationUtils_1.isValidObjectId; } });
229
234
  Object.defineProperty(exports, "validateAndSanitizeUserInput", { enumerable: true, get: function () { return validationUtils_1.validateAndSanitizeUserInput; } });
230
235
  // ---------------------------------------------------------------------------
236
+ // Text normalization
237
+ // ---------------------------------------------------------------------------
238
+ var textNormalization_1 = require("./utils/textNormalization");
239
+ Object.defineProperty(exports, "normalizeInlineText", { enumerable: true, get: function () { return textNormalization_1.normalizeInlineText; } });
240
+ Object.defineProperty(exports, "normalizeMultilineText", { enumerable: true, get: function () { return textNormalization_1.normalizeMultilineText; } });
241
+ // ---------------------------------------------------------------------------
231
242
  // Logging
232
243
  // ---------------------------------------------------------------------------
233
244
  var loggerUtils_1 = require("./utils/loggerUtils");
@@ -368,14 +368,18 @@ function OxyServicesAssetsMixin(Base) {
368
368
  errorMessage = error.message || errorMessage;
369
369
  }
370
370
  else if (error && typeof error === 'object') {
371
- if ('message' in error) {
372
- errorMessage = String(error.message) || errorMessage;
371
+ const errObj = error;
372
+ if ('message' in errObj) {
373
+ errorMessage = String(errObj.message) || errorMessage;
373
374
  }
374
- else if ('error' in error && typeof error.error === 'string') {
375
- errorMessage = error.error;
375
+ else if (typeof errObj.error === 'string') {
376
+ errorMessage = errObj.error;
376
377
  }
377
- else if ('data' in error && error.data?.message) {
378
- errorMessage = String(error.data.message);
378
+ else if (errObj.data && typeof errObj.data === 'object') {
379
+ const dataObj = errObj.data;
380
+ if (dataObj.message) {
381
+ errorMessage = String(dataObj.message);
382
+ }
379
383
  }
380
384
  }
381
385
  else if (error) {
@@ -58,29 +58,30 @@ function OxyServicesLanguageMixin(Base) {
58
58
  }
59
59
  }
60
60
  /**
61
- * Get the current language from storage or user profile
61
+ * Get the current locale from the user profile or local storage.
62
62
  * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
63
- * @returns The current language code (e.g., 'en-US') or null if not set
63
+ * @returns The current BCP-47 locale (e.g., 'en-US') or null if not set
64
64
  */
65
65
  async getCurrentLanguage(storageKeyPrefix = 'oxy_session') {
66
66
  try {
67
- // First try to get from user profile if authenticated
67
+ // First try the authenticated user's primary account locale.
68
68
  try {
69
69
  const user = await this.getCurrentUser();
70
- const userLanguage = user?.language;
71
- if (userLanguage) {
72
- return (0, languageUtils_1.normalizeLanguageCode)(userLanguage) || userLanguage;
70
+ const primary = (0, languageUtils_1.getPrimaryLanguage)(user);
71
+ if (primary) {
72
+ return primary;
73
73
  }
74
74
  }
75
- catch (e) {
76
- // User not authenticated or error, continue to storage
75
+ catch {
76
+ // Not authenticated or the profile fetch failed — fall through to the
77
+ // locally stored preference below.
77
78
  }
78
- // Fall back to storage
79
+ // Fall back to the locally stored locale preference.
79
80
  const storage = await this.getStorage();
80
81
  const storageKey = `${storageKeyPrefix}_language`;
81
82
  const storedLanguage = await storage.getItem(storageKey);
82
83
  if (storedLanguage) {
83
- return (0, languageUtils_1.normalizeLanguageCode)(storedLanguage) || storedLanguage;
84
+ return (0, languageUtils_1.normalizeLocale)(storedLanguage) ?? storedLanguage;
84
85
  }
85
86
  return null;
86
87
  }
@@ -73,6 +73,9 @@ function OxyServicesPrivacyMixin(Base) {
73
73
  cache: false,
74
74
  });
75
75
  this.clearCacheEntry('GET:/privacy/blocked');
76
+ // The block changed the viewer's graph (`blockedIds`) — bust the cached
77
+ // consolidated `GET /users/me/graph` so the next read reflects it.
78
+ this.clearCacheEntry('GET:/users/me/graph');
76
79
  return result;
77
80
  }
78
81
  catch (error) {
@@ -96,6 +99,9 @@ function OxyServicesPrivacyMixin(Base) {
96
99
  cache: false,
97
100
  });
98
101
  this.clearCacheEntry('GET:/privacy/blocked');
102
+ // Symmetric to blockUser: the unblock changed the viewer's `blockedIds`,
103
+ // so bust the consolidated `GET /users/me/graph` cache.
104
+ this.clearCacheEntry('GET:/users/me/graph');
99
105
  return result;
100
106
  }
101
107
  catch (error) {
@@ -512,6 +512,10 @@ function OxyServicesUserMixin(Base) {
512
512
  try {
513
513
  const result = await this.makeRequest('POST', `/users/${userId}/follow`, undefined, { cache: false });
514
514
  this.clearCacheEntry(`GET:/users/${userId}/follow-status`);
515
+ // The follow changed the viewer's graph — bust the cached consolidated
516
+ // `GET /users/me/graph` so the next read reflects the new following/
517
+ // mutual set instead of the stale pre-write snapshot.
518
+ this.clearCacheEntry('GET:/users/me/graph');
515
519
  return result;
516
520
  }
517
521
  catch (error) {
@@ -536,6 +540,8 @@ function OxyServicesUserMixin(Base) {
536
540
  for (const id of userIds) {
537
541
  this.clearCacheEntry(`GET:/users/${id}/follow-status`);
538
542
  }
543
+ // The batch changed the viewer's graph — bust the consolidated cache.
544
+ this.clearCacheEntry('GET:/users/me/graph');
539
545
  return result;
540
546
  }
541
547
  catch (error) {
@@ -560,6 +566,8 @@ function OxyServicesUserMixin(Base) {
560
566
  for (const id of userIds) {
561
567
  this.clearCacheEntry(`GET:/users/${id}/follow-status`);
562
568
  }
569
+ // The batch changed the viewer's graph — bust the consolidated cache.
570
+ this.clearCacheEntry('GET:/users/me/graph');
563
571
  return result;
564
572
  }
565
573
  catch (error) {
@@ -574,6 +582,8 @@ function OxyServicesUserMixin(Base) {
574
582
  const result = await this.makeRequest('DELETE', `/users/${userId}/follow`, undefined, { cache: false });
575
583
  // Bust the cached follow-status so a remount reads fresh truth (see `followUser`).
576
584
  this.clearCacheEntry(`GET:/users/${userId}/follow-status`);
585
+ // The unfollow changed the viewer's graph — bust the consolidated cache.
586
+ this.clearCacheEntry('GET:/users/me/graph');
577
587
  return result;
578
588
  }
579
589
  catch (error) {
@@ -705,6 +715,36 @@ function OxyServicesUserMixin(Base) {
705
715
  throw this.handleError(error);
706
716
  }
707
717
  }
718
+ /**
719
+ * Get the authenticated VIEWER's OWN social graph — the accounts they follow,
720
+ * the subset who follow back (mutuals), and the accounts they have blocked —
721
+ * as ONE ids-only payload. The viewer is derived server-side from the SDK's
722
+ * auth token (never a param).
723
+ *
724
+ * Consolidates what were three separate round trips (`getUserFollowing` /
725
+ * `getMutualUserIds` / `getBlockedUsers`) into a single request so a consumer
726
+ * can prime its whole viewer graph at once. Mirrors {@link getMutualUserIds}'s
727
+ * caching posture (2-minute identity-scoped cache); the follow/unfollow/block/
728
+ * unblock write methods bust this entry so a local mutation is reflected
729
+ * immediately. An anonymous caller resolves to empty lists.
730
+ */
731
+ async getViewerGraph() {
732
+ try {
733
+ const response = await this.makeRequest('GET', '/users/me/graph', undefined, {
734
+ cache: true,
735
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
736
+ });
737
+ const graph = response.data;
738
+ return {
739
+ followingIds: graph?.followingIds || [],
740
+ mutualIds: graph?.mutualIds || [],
741
+ blockedIds: graph?.blockedIds || [],
742
+ };
743
+ }
744
+ catch (error) {
745
+ throw this.handleError(error);
746
+ }
747
+ }
708
748
  /**
709
749
  * Get notifications
710
750
  */
@@ -164,7 +164,7 @@ function ipv6ToGroups(ip) {
164
164
  for (const part of segment.split(':')) {
165
165
  if (!/^[0-9a-fA-F]{1,4}$/.test(part))
166
166
  return null;
167
- groups.push(parseInt(part, 16));
167
+ groups.push(Number.parseInt(part, 16));
168
168
  }
169
169
  return groups;
170
170
  };
@@ -214,8 +214,8 @@ function extractEmbeddedIpv4(ip) {
214
214
  // Hex form "::ffff:0102:0304" → 1.2.3.4
215
215
  const hexMapped = lower.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
216
216
  if (hexMapped) {
217
- const hi = parseInt(hexMapped[1], 16);
218
- const lo = parseInt(hexMapped[2], 16);
217
+ const hi = Number.parseInt(hexMapped[1], 16);
218
+ const lo = Number.parseInt(hexMapped[2], 16);
219
219
  return `${(hi >> 8) & 0xff}.${hi & 0xff}.${(lo >> 8) & 0xff}.${lo & 0xff}`;
220
220
  }
221
221
  return null;
@@ -277,7 +277,7 @@ class SessionClient {
277
277
  transports: ['websocket'],
278
278
  autoConnect: true,
279
279
  reconnection: true,
280
- reconnectionAttempts: Infinity,
280
+ reconnectionAttempts: Number.POSITIVE_INFINITY,
281
281
  reconnectionDelay: 1000,
282
282
  reconnectionDelayMax: 10000,
283
283
  auth: (cb) => {
@@ -24,9 +24,9 @@ exports.getContrastTextColor = exports.isLightColor = exports.withOpacity = expo
24
24
  */
25
25
  const darkenColor = (color, factor = 0.6) => {
26
26
  const hex = color.replace('#', '');
27
- const r = parseInt(hex.substring(0, 2), 16);
28
- const g = parseInt(hex.substring(2, 4), 16);
29
- const b = parseInt(hex.substring(4, 6), 16);
27
+ const r = Number.parseInt(hex.substring(0, 2), 16);
28
+ const g = Number.parseInt(hex.substring(2, 4), 16);
29
+ const b = Number.parseInt(hex.substring(4, 6), 16);
30
30
  const newR = Math.max(0, Math.round(r * (1 - factor)));
31
31
  const newG = Math.max(0, Math.round(g * (1 - factor)));
32
32
  const newB = Math.max(0, Math.round(b * (1 - factor)));
@@ -47,9 +47,9 @@ exports.darkenColor = darkenColor;
47
47
  */
48
48
  const lightenColor = (color, factor = 0.3) => {
49
49
  const hex = color.replace('#', '');
50
- const r = parseInt(hex.substring(0, 2), 16);
51
- const g = parseInt(hex.substring(2, 4), 16);
52
- const b = parseInt(hex.substring(4, 6), 16);
50
+ const r = Number.parseInt(hex.substring(0, 2), 16);
51
+ const g = Number.parseInt(hex.substring(2, 4), 16);
52
+ const b = Number.parseInt(hex.substring(4, 6), 16);
53
53
  const newR = Math.min(255, Math.round(r + (255 - r) * factor));
54
54
  const newG = Math.min(255, Math.round(g + (255 - g) * factor));
55
55
  const newB = Math.min(255, Math.round(b + (255 - b) * factor));
@@ -71,9 +71,9 @@ const hexToRgb = (hex) => {
71
71
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
72
72
  return result
73
73
  ? {
74
- r: parseInt(result[1], 16),
75
- g: parseInt(result[2], 16),
76
- b: parseInt(result[3], 16),
74
+ r: Number.parseInt(result[1], 16),
75
+ g: Number.parseInt(result[2], 16),
76
+ b: Number.parseInt(result[3], 16),
77
77
  }
78
78
  : null;
79
79
  };