@oxyhq/core 15.0.1 → 16.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 (39) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/OxyServices.errors.js +33 -1
  3. package/dist/cjs/OxyServices.js +2 -1
  4. package/dist/cjs/index.js +8 -5
  5. package/dist/cjs/mixins/OxyServices.assets.js +31 -8
  6. package/dist/cjs/mixins/OxyServices.deviceBoot.js +5 -5
  7. package/dist/cjs/utils/accountUtils.js +6 -1
  8. package/dist/cjs/utils/displayNamePolicyRanges.generated.js +28 -3
  9. package/dist/cjs/utils/validationUtils.js +110 -21
  10. package/dist/esm/.tsbuildinfo +1 -1
  11. package/dist/esm/OxyServices.errors.js +31 -0
  12. package/dist/esm/OxyServices.js +2 -2
  13. package/dist/esm/index.js +2 -2
  14. package/dist/esm/mixins/OxyServices.assets.js +32 -9
  15. package/dist/esm/mixins/OxyServices.deviceBoot.js +5 -5
  16. package/dist/esm/utils/accountUtils.js +6 -1
  17. package/dist/esm/utils/displayNamePolicyRanges.generated.js +27 -2
  18. package/dist/esm/utils/validationUtils.js +110 -21
  19. package/dist/types/.tsbuildinfo +1 -1
  20. package/dist/types/OxyServices.d.ts +2 -2
  21. package/dist/types/OxyServices.errors.d.ts +33 -0
  22. package/dist/types/index.d.ts +2 -2
  23. package/dist/types/mixins/OxyServices.assets.d.ts +17 -5
  24. package/dist/types/mixins/OxyServices.deviceBoot.d.ts +5 -5
  25. package/dist/types/utils/displayNamePolicyRanges.generated.d.ts +27 -2
  26. package/dist/types/utils/validationUtils.d.ts +104 -20
  27. package/package.json +2 -2
  28. package/src/OxyServices.errors.ts +45 -0
  29. package/src/OxyServices.ts +2 -2
  30. package/src/index.ts +3 -1
  31. package/src/mixins/OxyServices.assets.ts +36 -9
  32. package/src/mixins/OxyServices.deviceBoot.ts +5 -5
  33. package/src/mixins/__tests__/OxyServices.serviceAssetMetadata.test.ts +52 -3
  34. package/src/utils/__tests__/accountUtils.test.ts +22 -0
  35. package/src/utils/__tests__/coldBoot.test.ts +9 -4
  36. package/src/utils/__tests__/validationUtils.test.ts +292 -1
  37. package/src/utils/accountUtils.ts +9 -1
  38. package/src/utils/displayNamePolicyRanges.generated.ts +31 -2
  39. package/src/utils/validationUtils.ts +113 -20
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OxyAuthenticationTimeoutError = exports.AssetUrlResolutionError = exports.OxyAuthenticationError = void 0;
3
+ exports.OxyAuthenticationTimeoutError = exports.ServiceAssetMetadataError = exports.AssetUrlResolutionError = exports.OxyAuthenticationError = void 0;
4
4
  /**
5
5
  * Custom error types for better error handling
6
6
  */
@@ -54,6 +54,38 @@ class AssetUrlResolutionError extends Error {
54
54
  }
55
55
  }
56
56
  exports.AssetUrlResolutionError = AssetUrlResolutionError;
57
+ /**
58
+ * Thrown when one or more chunks of `getServiceAssetMetadataByIds` could not be
59
+ * resolved.
60
+ *
61
+ * Exists because for this endpoint a FAILED request and an ABSENT asset produce
62
+ * the same observable result. The server legitimately omits unknown/deleted ids,
63
+ * so callers are documented to map the response by `id` and treat a missing
64
+ * entry as "no such asset" — which means a chunk that 429s, times out or 5xxs
65
+ * reads as authoritative absence unless it is raised.
66
+ *
67
+ * That was not hypothetical: a metadata backfill counted every throttled asset
68
+ * as needing no update and exited 0, and the MTN signed-record builder embedded
69
+ * media with no content hash into records that are immutable once signed. Both
70
+ * paths reported success and wrote nothing.
71
+ *
72
+ * `unresolvedIds` carries every id in a failed chunk — not the subset the server
73
+ * would have omitted anyway, which is unknowable when the request never landed.
74
+ * A caller that wants best-effort passes `{ partial: true }` and never sees this.
75
+ */
76
+ class ServiceAssetMetadataError extends Error {
77
+ constructor(unresolvedIds, statuses, cause) {
78
+ const uniqueStatuses = Array.from(new Set(statuses)).sort((a, b) => a - b);
79
+ const statusSuffix = uniqueStatuses.length > 0 ? ` — status ${uniqueStatuses.join(', ')}` : '';
80
+ super(`Could not resolve asset metadata for ${unresolvedIds.length} id(s)${statusSuffix}. Treat this as unknown, not as absent; pass { partial: true } for best-effort.`);
81
+ this.code = 'SERVICE_ASSET_METADATA_UNRESOLVED';
82
+ this.name = 'ServiceAssetMetadataError';
83
+ this.unresolvedIds = unresolvedIds;
84
+ this.statuses = uniqueStatuses;
85
+ this.cause = cause;
86
+ }
87
+ }
88
+ exports.ServiceAssetMetadataError = ServiceAssetMetadataError;
57
89
  class OxyAuthenticationTimeoutError extends OxyAuthenticationError {
58
90
  constructor(operationName, timeoutMs) {
59
91
  super(`Authentication timeout (${timeoutMs}ms): ${operationName} requires user authentication. Please ensure the user is logged in before calling this method.`, 'AUTH_TIMEOUT', 408);
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.oxyClient = exports.OXY_API_URL = exports.OXY_CLOUD_URL = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.AssetUrlResolutionError = exports.OxyServices = void 0;
3
+ exports.oxyClient = exports.OXY_API_URL = exports.OXY_CLOUD_URL = exports.ServiceAssetMetadataError = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.AssetUrlResolutionError = exports.OxyServices = void 0;
4
4
  const OxyServices_errors_1 = require("./OxyServices.errors");
5
5
  Object.defineProperty(exports, "AssetUrlResolutionError", { enumerable: true, get: function () { return OxyServices_errors_1.AssetUrlResolutionError; } });
6
6
  Object.defineProperty(exports, "OxyAuthenticationError", { enumerable: true, get: function () { return OxyServices_errors_1.OxyAuthenticationError; } });
7
7
  Object.defineProperty(exports, "OxyAuthenticationTimeoutError", { enumerable: true, get: function () { return OxyServices_errors_1.OxyAuthenticationTimeoutError; } });
8
+ Object.defineProperty(exports, "ServiceAssetMetadataError", { enumerable: true, get: function () { return OxyServices_errors_1.ServiceAssetMetadataError; } });
8
9
  // Import mixin composition helper
9
10
  const mixins_1 = require("./mixins");
10
11
  /**
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.TopicType = 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.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.AssetUrlResolutionError = exports.OxyServices = void 0;
22
- 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 = 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 = void 0;
23
- exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = 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_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.isValidDisplayName = exports.isValidPassword = 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.buildQueryParams = exports.translate = void 0;
24
- exports.refreshDeviceSecretArm = exports.refreshPersistedSession = exports.AccountNotOnDeviceError = exports.establishIdentitySession = 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 = void 0;
25
- exports.packageInfo = exports.runSessionColdBoot = exports.TOKEN_REFRESH_LEAD_MS = exports.startTokenRefreshScheduler = exports.installAuthRefreshHandler = exports.createAuthRefreshHandler = void 0;
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.createQuickAccount = 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.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.establishIdentitySession = 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 = void 0;
25
+ exports.packageInfo = exports.runSessionColdBoot = exports.TOKEN_REFRESH_LEAD_MS = exports.startTokenRefreshScheduler = exports.installAuthRefreshHandler = exports.createAuthRefreshHandler = exports.refreshDeviceSecretArm = exports.refreshPersistedSession = exports.AccountNotOnDeviceError = void 0;
26
26
  // Ensure crypto polyfills are loaded before anything else
27
27
  require("./crypto/polyfill");
28
28
  // ---------------------------------------------------------------------------
@@ -33,6 +33,7 @@ Object.defineProperty(exports, "OxyServices", { enumerable: true, get: function
33
33
  Object.defineProperty(exports, "AssetUrlResolutionError", { enumerable: true, get: function () { return OxyServices_1.AssetUrlResolutionError; } });
34
34
  Object.defineProperty(exports, "OxyAuthenticationError", { enumerable: true, get: function () { return OxyServices_1.OxyAuthenticationError; } });
35
35
  Object.defineProperty(exports, "OxyAuthenticationTimeoutError", { enumerable: true, get: function () { return OxyServices_1.OxyAuthenticationTimeoutError; } });
36
+ Object.defineProperty(exports, "ServiceAssetMetadataError", { enumerable: true, get: function () { return OxyServices_1.ServiceAssetMetadataError; } });
36
37
  var OxyServices_2 = require("./OxyServices");
37
38
  Object.defineProperty(exports, "OXY_CLOUD_URL", { enumerable: true, get: function () { return OxyServices_2.OXY_CLOUD_URL; } });
38
39
  Object.defineProperty(exports, "oxyClient", { enumerable: true, get: function () { return OxyServices_2.oxyClient; } });
@@ -241,6 +242,7 @@ var validationUtils_1 = require("./utils/validationUtils");
241
242
  Object.defineProperty(exports, "EMAIL_REGEX", { enumerable: true, get: function () { return validationUtils_1.EMAIL_REGEX; } });
242
243
  Object.defineProperty(exports, "USERNAME_REGEX", { enumerable: true, get: function () { return validationUtils_1.USERNAME_REGEX; } });
243
244
  Object.defineProperty(exports, "PASSWORD_REGEX", { enumerable: true, get: function () { return validationUtils_1.PASSWORD_REGEX; } });
245
+ Object.defineProperty(exports, "MAX_DISPLAY_NAME_LENGTH", { enumerable: true, get: function () { return validationUtils_1.MAX_DISPLAY_NAME_LENGTH; } });
244
246
  Object.defineProperty(exports, "isValidEmail", { enumerable: true, get: function () { return validationUtils_1.isValidEmail; } });
245
247
  Object.defineProperty(exports, "isValidUsername", { enumerable: true, get: function () { return validationUtils_1.isValidUsername; } });
246
248
  Object.defineProperty(exports, "isValidPassword", { enumerable: true, get: function () { return validationUtils_1.isValidPassword; } });
@@ -248,6 +250,7 @@ Object.defineProperty(exports, "isValidDisplayName", { enumerable: true, get: fu
248
250
  Object.defineProperty(exports, "DISPLAY_NAME_ALLOWED_SCRIPTS", { enumerable: true, get: function () { return validationUtils_1.DISPLAY_NAME_ALLOWED_SCRIPTS; } });
249
251
  Object.defineProperty(exports, "DISPLAY_NAME_DISALLOWED_SOURCE", { enumerable: true, get: function () { return validationUtils_1.DISPLAY_NAME_DISALLOWED_SOURCE; } });
250
252
  Object.defineProperty(exports, "DISPLAY_NAME_ORPHANED_MARK_SOURCE", { enumerable: true, get: function () { return validationUtils_1.DISPLAY_NAME_ORPHANED_MARK_SOURCE; } });
253
+ Object.defineProperty(exports, "DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE", { enumerable: true, get: function () { return validationUtils_1.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE; } });
251
254
  Object.defineProperty(exports, "isRequiredString", { enumerable: true, get: function () { return validationUtils_1.isRequiredString; } });
252
255
  Object.defineProperty(exports, "isRequiredNumber", { enumerable: true, get: function () { return validationUtils_1.isRequiredNumber; } });
253
256
  Object.defineProperty(exports, "isRequiredBoolean", { enumerable: true, get: function () { return validationUtils_1.isRequiredBoolean; } });
@@ -303,15 +303,25 @@ function OxyServicesAssetsMixin(Base) {
303
303
  * throws because no credentials are available. A plain user-session request
304
304
  * is rejected by the route's service-auth guard.
305
305
  *
306
- * Resilience: chunks are independent. A failed chunk is logged and skipped —
307
- * the method returns every entry that resolved successfully rather than
308
- * discarding the whole call on one chunk's failure. An empty/whitespace-only
309
- * input resolves immediately with `[]` and performs no network call.
306
+ * FAILURE IS NOT ABSENCE. The server legitimately omits unknown/deleted ids,
307
+ * so a short result is normal — which means a chunk that FAILED (a 429, a
308
+ * timeout, a 5xx) is indistinguishable from "those assets don't exist" if it
309
+ * simply contributes nothing. This method used to swallow a failed chunk and
310
+ * return the rest, so every caller silently read a throttled request as "no
311
+ * metadata": a backfill counted the asset as needing no update, and the
312
+ * signed-record builder embedded a media item with no hash. Both reported
313
+ * success while writing nothing, and the MTN chain's records are immutable.
314
+ *
315
+ * So a failed chunk THROWS {@link ServiceAssetMetadataError} by default,
316
+ * carrying the ids it could not resolve. A caller that genuinely wants
317
+ * best-effort opts in with `{ partial: true }` and gets the old behaviour
318
+ * explicitly. An empty/whitespace-only input resolves immediately with `[]`
319
+ * and performs no network call.
310
320
  *
311
321
  * Not cached at the SDK layer: it's a POST keyed on a multi-id body (low hit
312
322
  * rate), mirroring the sibling service/POST methods which never cache.
313
323
  */
314
- async getServiceAssetMetadataByIds(ids) {
324
+ async getServiceAssetMetadataByIds(ids, options = {}) {
315
325
  const uniqueIds = Array.from(new Set(ids.filter((id) => typeof id === 'string' && id.trim().length > 0)));
316
326
  if (uniqueIds.length === 0) {
317
327
  return [];
@@ -320,22 +330,35 @@ function OxyServicesAssetsMixin(Base) {
320
330
  for (let i = 0; i < uniqueIds.length; i += SERVICE_ASSET_METADATA_CHUNK_SIZE) {
321
331
  chunks.push(uniqueIds.slice(i, i + SERVICE_ASSET_METADATA_CHUNK_SIZE));
322
332
  }
323
- // Run chunks concurrently; a single chunk failure must not sink the rest.
333
+ // Chunks stay independent so one failure never cancels work already in
334
+ // flight; the failures are collected and re-raised together below.
335
+ const unresolvedIds = [];
336
+ const statuses = [];
337
+ let firstError;
324
338
  const settled = await Promise.all(chunks.map(async (chunk) => {
325
339
  try {
326
340
  const entries = await this.makeServiceRequest('POST', '/assets/service/by-ids', { ids: chunk });
327
341
  return Array.isArray(entries) ? entries : [];
328
342
  }
329
343
  catch (error) {
330
- logger_1.logger.warn('getServiceAssetMetadataByIds: chunk failed, continuing with remaining chunks', {
344
+ const status = (0, errorUtils_1.extractErrorStatus)(error);
345
+ logger_1.logger.warn('getServiceAssetMetadataByIds: chunk failed', {
331
346
  method: 'getServiceAssetMetadataByIds',
332
347
  chunkSize: chunk.length,
333
- status: (0, errorUtils_1.extractErrorStatus)(error),
348
+ status,
349
+ partial: options.partial === true,
334
350
  error: error instanceof Error ? error.message : String(error),
335
351
  });
352
+ unresolvedIds.push(...chunk);
353
+ if (typeof status === 'number')
354
+ statuses.push(status);
355
+ firstError ?? (firstError = error);
336
356
  return [];
337
357
  }
338
358
  }));
359
+ if (unresolvedIds.length > 0 && options.partial !== true) {
360
+ throw new OxyServices_errors_1.ServiceAssetMetadataError(unresolvedIds, statuses, firstError);
361
+ }
339
362
  return settled.flat();
340
363
  }
341
364
  /**
@@ -156,11 +156,11 @@ function OxyServicesDeviceBootMixin(Base) {
156
156
  *
157
157
  * That paragraph is LOAD-BEARING, not belt-and-braces: the route sits above
158
158
  * oxy-api's router-wide origin guard (deliberately, so a native client with
159
- * no `Origin` is not rejected), so as of this writing NOTHING server-side
160
- * refuses a browser caller that presents a valid bearer. Until a server-side
161
- * check lands, caller discipline is the only control which is also why a
162
- * doc note cannot be the whole answer to browser XSS minting a long-lived
163
- * credential with the victim's bearer.
159
+ * no `Origin` is not rejected). oxy-api additionally refuses callers that
160
+ * carry browser context signals (`Origin` or `Sec-Fetch-Site`) with
161
+ * `403 browser_not_allowed` native HTTP clients send neither. Gate the
162
+ * caller by platform on the client as well; do not widen the 404 degrade to
163
+ * 403, which would also swallow a genuine origin misconfiguration.
164
164
  *
165
165
  * @returns the provisioned credential, or `null` when the endpoint is absent
166
166
  * (404). The API deploy leads the SDK release, so a client on a newer SDK
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.getAccountColor = exports.createQuickAccount = exports.buildAccountsArray = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.formatPublicKeyHandle = void 0;
8
8
  const i18n_1 = require("../i18n");
9
+ const userHandle_1 = require("./userHandle");
9
10
  /**
10
11
  * Truncate a long public key for display, e.g. `0x12345678…`.
11
12
  * Falls back to the raw key if it's too short to truncate.
@@ -103,7 +104,11 @@ exports.buildAccountsArray = buildAccountsArray;
103
104
  * @param getFileDownloadUrl - Function to generate avatar download URL from file ID
104
105
  */
105
106
  const createQuickAccount = (sessionId, userData, existingAccount, getFileDownloadUrl) => {
106
- const displayName = (0, exports.getAccountDisplayName)(userData);
107
+ const nameObj = userData.name && typeof userData.name === 'object' ? userData.name : undefined;
108
+ const apiDisplayName = typeof nameObj?.displayName === 'string' ? nameObj.displayName.trim() : '';
109
+ const displayName = apiDisplayName ||
110
+ (0, userHandle_1.getNormalizedUserHandle)(userData) ||
111
+ (0, exports.getAccountDisplayName)(null);
107
112
  const userId = userData.id || (typeof userData._id === 'string' ? userData._id : userData._id?.toString());
108
113
  // Preserve existing avatarUrl if avatar hasn't changed (prevents image reload)
109
114
  let avatarUrl;
@@ -18,7 +18,30 @@
18
18
  *
19
19
  * Classes captured (regexpu-core, u-mode):
20
20
  * - DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES: the 30-script Script_Extensions
21
- * allowlist (scx=Latin, scx=Greek, … scx=Han).
21
+ * allowlist (scx=Latin, scx=Greek, … scx=Han) INTERSECTED with
22
+ * General_Category L, MINUS an explicit code-point denylist. The
23
+ * intersection is load-bearing: `scx=X` also carries script X's digits,
24
+ * punctuation and symbols, so without it the class admitted 1831 non-letter
25
+ * code points — script digits, 1082 symbols, and 9 invisible format/control
26
+ * characters including the U+061C bidi control. The generator fails if any
27
+ * non-letter survives. The denylist covers the opposite case: code points
28
+ * that ARE letters of an allowlisted script yet function as hate symbols
29
+ * (卐 卍) — no script-level or category-level rule can exclude
30
+ * them without also rejecting every real Chinese, Japanese and Korean name.
31
+ * - DISPLAY_NAME_DENIED_SYMBOL_LETTERS_RANGES: that denylist on its own. NOT
32
+ * used to build any runtime regex — the code points are already subtracted
33
+ * from the allowlist above, so the policy enforces them with no extra probe.
34
+ * It is emitted so tests can enumerate what is denied and assert each entry
35
+ * is actually rejected.
36
+ * - DISPLAY_NAME_NAME_SEPARATORS_RANGES: the four punctuation code points that
37
+ * JOIN two letters inside one real name
38
+ * (· ־ ་ ・). All are General_Category P,
39
+ * so the letters intersection strips them by default; they are re-admitted
40
+ * ONLY between two letters. Unlike the denylist, this class DOES build a
41
+ * runtime regex — the conditional half lives in
42
+ * `DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE`, which strips any of them that
43
+ * is not letter-flanked on both sides, so decorative use
44
+ * (a trailing `Roberto ·`) keeps being trimmed.
22
45
  * - DISPLAY_NAME_COMBINING_MARKS_RANGES: General_Category M (combining marks).
23
46
  * - DISPLAY_NAME_SPACE_SEPARATORS_RANGES: General_Category Zs (space
24
47
  * separators).
@@ -28,8 +51,10 @@
28
51
  * REGENERATE: cd packages/core && bun run generate:display-name-policy
29
52
  */
30
53
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.DISPLAY_NAME_LETTERS_RANGES = exports.DISPLAY_NAME_SPACE_SEPARATORS_RANGES = exports.DISPLAY_NAME_COMBINING_MARKS_RANGES = exports.DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES = void 0;
32
- exports.DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES = 'A-Za-z\\xAA\\xB7\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02B8\\u02BC\\u02C7\\u02C9-\\u02CB\\u02CD\\u02D7\\u02D9\\u02E0-\\u02E4\\u02EA\\u02EB\\u0300-\\u030E\\u0310\\u0311\\u0313\\u0323-\\u0325\\u032D\\u032E\\u0330\\u0331\\u0342\\u0345\\u0358\\u035E\\u0363-\\u0377\\u037A-\\u037D\\u037F\\u0384\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03E1\\u03F0-\\u052F\\u0531-\\u0556\\u0559-\\u058A\\u058D-\\u058F\\u0591-\\u05C7\\u05D0-\\u05EA\\u05EF-\\u05F4\\u0600-\\u0604\\u0606-\\u06DC\\u06DE-\\u06FF\\u0750-\\u07B1\\u0870-\\u0891\\u0897-\\u08E1\\u08E3-\\u0952\\u0955-\\u0983\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE\\u09D7\\u09DC\\u09DD\\u09DF-\\u09E3\\u09E6-\\u09FE\\u0A01-\\u0A03\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A59-\\u0A5C\\u0A5E\\u0A66-\\u0A76\\u0A81-\\u0A83\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-\\u0AF1\\u0AF9-\\u0AFF\\u0B01-\\u0B03\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3C-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B5C\\u0B5D\\u0B5F-\\u0B63\\u0B66-\\u0B77\\u0B82\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD0\\u0BD7\\u0BE6-\\u0BFA\\u0C00-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3C-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C58-\\u0C5A\\u0C5C\\u0C5D\\u0C60-\\u0C63\\u0C66-\\u0C6F\\u0C77-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CDC-\\u0CDE\\u0CE0-\\u0CE3\\u0CE6-\\u0CEF\\u0CF1-\\u0CF3\\u0D00-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4F\\u0D54-\\u0D63\\u0D66-\\u0D7F\\u0D81-\\u0D83\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DE6-\\u0DEF\\u0DF2-\\u0DF4\\u0E01-\\u0E3A\\u0E40-\\u0E5B\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EC8-\\u0ECE\\u0ED0-\\u0ED9\\u0EDC-\\u0EDF\\u0F00-\\u0F47\\u0F49-\\u0F6C\\u0F71-\\u0F97\\u0F99-\\u0FBC\\u0FBE-\\u0FCC\\u0FCE-\\u0FD4\\u0FD9\\u0FDA\\u1000-\\u10C5\\u10C7\\u10CD\\u10D0-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-\\u137C\\u1380-\\u1399\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1780-\\u17DD\\u17E0-\\u17E9\\u17F0-\\u17F9\\u1800-\\u1819\\u1820-\\u1878\\u1880-\\u18AA\\u19E0-\\u19FF\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CD0-\\u1CF9\\u1D00-\\u1DC1\\u1DF8\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FC4\\u1FC6-\\u1FD3\\u1FD6-\\u1FDB\\u1FDD-\\u1FEF\\u1FF2-\\u1FF4\\u1FF6-\\u1FFE\\u202F\\u204F\\u205A\\u205D\\u2071\\u207F\\u2090-\\u209C\\u20F0\\u2126\\u212A\\u212B\\u2132\\u214E\\u2160-\\u2188\\u2C60-\\u2C7F\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2DE0-\\u2DFF\\u2E17\\u2E31\\u2E41\\u2E43\\u2E80-\\u2E99\\u2E9B-\\u2EF3\\u2F00-\\u2FD5\\u2FF0-\\u2FFF\\u3001-\\u3003\\u3005-\\u3011\\u3013-\\u301F\\u302A-\\u3035\\u3021-\\u302D\\u3037-\\u303F\\u3041-\\u3096\\u3099-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u3190-\\u31E5\\u31EF-\\u321E\\u3220-\\u3247\\u3260-\\u327E\\u3280-\\u32B0\\u32C0-\\u32CB\\u32D0-\\u3370\\u337B-\\u337F\\u33E0-\\u33FE\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uA640-\\uA69F\\uA700-\\uA707\\uA722-\\uA787\\uA78B-\\uA7DC\\uA7F1-\\uA7FF\\uA830-\\uA839\\uA8E0-\\uA8FF\\uA92E\\uA960-\\uA97C\\uA9E0-\\uA9FE\\uAA60-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABBF\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFDCF\\uFDF0-\\uFDFF\\uFE2E\\uFE2F\\uFE45\\uFE46\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF61-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10140}-\\u{1018E}\\u{101A0}\\u{102E0}-\\u{102FB}\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10E60}-\\u{10E7E}\\u{10EC2}-\\u{10EC7}\\u{10ED0}-\\u{10ED8}\\u{10EFA}-\\u{10EFF}\\u{111E1}-\\u{111F4}\\u{11301}\\u{11303}\\u{1133B}\\u{1133C}\\u{11660}-\\u{1166C}\\u{116D0}-\\u{116E3}\\u{11B00}-\\u{11B09}\\u{11FC0}-\\u{11FF1}\\u{11FFF}\\u{16FE2}\\u{16FE3}\\u{16FF0}-\\u{16FF6}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1D200}-\\u{1D245}\\u{1D360}-\\u{1D371}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E08F}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{1EEF0}\\u{1EEF1}\\u{1F200}\\u{1F250}\\u{1F251}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}';
54
+ exports.DISPLAY_NAME_NAME_SEPARATORS_RANGES = exports.DISPLAY_NAME_DENIED_SYMBOL_LETTERS_RANGES = exports.DISPLAY_NAME_LETTERS_RANGES = exports.DISPLAY_NAME_SPACE_SEPARATORS_RANGES = exports.DISPLAY_NAME_COMBINING_MARKS_RANGES = exports.DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES = void 0;
55
+ exports.DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES = 'A-Za-z\\xAA\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02B8\\u02BC\\u02C7\\u02C9-\\u02CB\\u02CD\\u02E0-\\u02E4\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03E1\\u03F0-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0750-\\u07A5\\u07B1\\u0870-\\u0887\\u0889-\\u088F\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5C\\u0C5D\\u0C60\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDC-\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2126\\u212A\\u212B\\u2132\\u214E\\u2183\\u2184\\u2C60-\\u2C7F\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\u534C\\u534E\\u534F\\u5351-\\u9FFF\\uA640-\\uA66E\\uA67F-\\uA69D\\uA722-\\uA787\\uA78B-\\uA7DC\\uA7F1-\\uA7FF\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA960-\\uA97C\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA60-\\uAA76\\uAA7A\\uAA7E\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABBF\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10EC2}-\\u{10EC7}\\u{16FE3}\\u{16FF2}\\u{16FF3}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}';
33
56
  exports.DISPLAY_NAME_COMBINING_MARKS_RANGES = '\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u07FD\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u0897-\\u089F\\u08CA-\\u08E1\\u08E3-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2\\u09E3\\u09FE\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2\\u0AE3\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B62\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C00-\\u0C04\\u0C3C\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0C81-\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CE2\\u0CE3\\u0CF3\\u0D00-\\u0D03\\u0D3B\\u0D3C\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62\\u0D63\\u0D81-\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EBC\\u0EC8-\\u0ECE\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E\\u0F3F\\u0F71-\\u0F84\\u0F86\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1715\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u180F\\u1885\\u1886\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1AB0-\\u1ADD\\u1AE0-\\u1AEB\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF4\\u1CF7-\\u1CF9\\u1DC0-\\u1DFF\\u20D0-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F-\\uA672\\uA674-\\uA67D\\uA69E\\uA69F\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA82C\\uA880\\uA881\\uA8B4-\\uA8C5\\uA8E0-\\uA8F1\\uA8FF\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uA9E5\\uAA29-\\uAA36\\uAA43\\uAA4C\\uAA4D\\uAA7B-\\uAA7D\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5\\uAAF6\\uABE3-\\uABEA\\uABEC\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE2F\\u{101FD}\\u{102E0}\\u{10376}-\\u{1037A}\\u{10A01}-\\u{10A03}\\u{10A05}\\u{10A06}\\u{10A0C}-\\u{10A0F}\\u{10A38}-\\u{10A3A}\\u{10A3F}\\u{10AE5}\\u{10AE6}\\u{10D24}-\\u{10D27}\\u{10D69}-\\u{10D6D}\\u{10EAB}\\u{10EAC}\\u{10EFA}-\\u{10EFF}\\u{10F46}-\\u{10F50}\\u{10F82}-\\u{10F85}\\u{11000}-\\u{11002}\\u{11038}-\\u{11046}\\u{11070}\\u{11073}\\u{11074}\\u{1107F}-\\u{11082}\\u{110B0}-\\u{110BA}\\u{110C2}\\u{11100}-\\u{11102}\\u{11127}-\\u{11134}\\u{11145}\\u{11146}\\u{11173}\\u{11180}-\\u{11182}\\u{111B3}-\\u{111C0}\\u{111C9}-\\u{111CC}\\u{111CE}\\u{111CF}\\u{1122C}-\\u{11237}\\u{1123E}\\u{11241}\\u{112DF}-\\u{112EA}\\u{11300}-\\u{11303}\\u{1133B}\\u{1133C}\\u{1133E}-\\u{11344}\\u{11347}\\u{11348}\\u{1134B}-\\u{1134D}\\u{11357}\\u{11362}\\u{11363}\\u{11366}-\\u{1136C}\\u{11370}-\\u{11374}\\u{113B8}-\\u{113C0}\\u{113C2}\\u{113C5}\\u{113C7}-\\u{113CA}\\u{113CC}-\\u{113D0}\\u{113D2}\\u{113E1}\\u{113E2}\\u{11435}-\\u{11446}\\u{1145E}\\u{114B0}-\\u{114C3}\\u{115AF}-\\u{115B5}\\u{115B8}-\\u{115C0}\\u{115DC}\\u{115DD}\\u{11630}-\\u{11640}\\u{116AB}-\\u{116B7}\\u{1171D}-\\u{1172B}\\u{1182C}-\\u{1183A}\\u{11930}-\\u{11935}\\u{11937}\\u{11938}\\u{1193B}-\\u{1193E}\\u{11940}\\u{11942}\\u{11943}\\u{119D1}-\\u{119D7}\\u{119DA}-\\u{119E0}\\u{119E4}\\u{11A01}-\\u{11A0A}\\u{11A33}-\\u{11A39}\\u{11A3B}-\\u{11A3E}\\u{11A47}\\u{11A51}-\\u{11A5B}\\u{11A8A}-\\u{11A99}\\u{11B60}-\\u{11B67}\\u{11C2F}-\\u{11C36}\\u{11C38}-\\u{11C3F}\\u{11C92}-\\u{11CA7}\\u{11CA9}-\\u{11CB6}\\u{11D31}-\\u{11D36}\\u{11D3A}\\u{11D3C}\\u{11D3D}\\u{11D3F}-\\u{11D45}\\u{11D47}\\u{11D8A}-\\u{11D8E}\\u{11D90}\\u{11D91}\\u{11D93}-\\u{11D97}\\u{11EF3}-\\u{11EF6}\\u{11F00}\\u{11F01}\\u{11F03}\\u{11F34}-\\u{11F3A}\\u{11F3E}-\\u{11F42}\\u{11F5A}\\u{13440}\\u{13447}-\\u{13455}\\u{1611E}-\\u{1612F}\\u{16AF0}-\\u{16AF4}\\u{16B30}-\\u{16B36}\\u{16F4F}\\u{16F51}-\\u{16F87}\\u{16F8F}-\\u{16F92}\\u{16FE4}\\u{16FF0}\\u{16FF1}\\u{1BC9D}\\u{1BC9E}\\u{1CF00}-\\u{1CF2D}\\u{1CF30}-\\u{1CF46}\\u{1D165}-\\u{1D169}\\u{1D16D}-\\u{1D172}\\u{1D17B}-\\u{1D182}\\u{1D185}-\\u{1D18B}\\u{1D1AA}-\\u{1D1AD}\\u{1D242}-\\u{1D244}\\u{1DA00}-\\u{1DA36}\\u{1DA3B}-\\u{1DA6C}\\u{1DA75}\\u{1DA84}\\u{1DA9B}-\\u{1DA9F}\\u{1DAA1}-\\u{1DAAF}\\u{1E000}-\\u{1E006}\\u{1E008}-\\u{1E018}\\u{1E01B}-\\u{1E021}\\u{1E023}\\u{1E024}\\u{1E026}-\\u{1E02A}\\u{1E08F}\\u{1E130}-\\u{1E136}\\u{1E2AE}\\u{1E2EC}-\\u{1E2EF}\\u{1E4EC}-\\u{1E4EF}\\u{1E5EE}\\u{1E5EF}\\u{1E6E3}\\u{1E6E6}\\u{1E6EE}\\u{1E6EF}\\u{1E6F5}\\u{1E8D0}-\\u{1E8D6}\\u{1E944}-\\u{1E94A}\\u{E0100}-\\u{E01EF}';
34
57
  exports.DISPLAY_NAME_SPACE_SEPARATORS_RANGES = ' \\xA0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000';
35
58
  exports.DISPLAY_NAME_LETTERS_RANGES = 'A-Za-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u0870-\\u0887\\u0889-\\u088F\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5C\\u0C5D\\u0C60\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDC-\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u1711\\u171F-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4C\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5\\u1CF6\\u1CFA\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7DC\\uA7F1-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10000}-\\u{1000B}\\u{1000D}-\\u{10026}\\u{10028}-\\u{1003A}\\u{1003C}\\u{1003D}\\u{1003F}-\\u{1004D}\\u{10050}-\\u{1005D}\\u{10080}-\\u{100FA}\\u{10280}-\\u{1029C}\\u{102A0}-\\u{102D0}\\u{10300}-\\u{1031F}\\u{1032D}-\\u{10340}\\u{10342}-\\u{10349}\\u{10350}-\\u{10375}\\u{10380}-\\u{1039D}\\u{103A0}-\\u{103C3}\\u{103C8}-\\u{103CF}\\u{10400}-\\u{1049D}\\u{104B0}-\\u{104D3}\\u{104D8}-\\u{104FB}\\u{10500}-\\u{10527}\\u{10530}-\\u{10563}\\u{10570}-\\u{1057A}\\u{1057C}-\\u{1058A}\\u{1058C}-\\u{10592}\\u{10594}\\u{10595}\\u{10597}-\\u{105A1}\\u{105A3}-\\u{105B1}\\u{105B3}-\\u{105B9}\\u{105BB}\\u{105BC}\\u{105C0}-\\u{105F3}\\u{10600}-\\u{10736}\\u{10740}-\\u{10755}\\u{10760}-\\u{10767}\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10800}-\\u{10805}\\u{10808}\\u{1080A}-\\u{10835}\\u{10837}\\u{10838}\\u{1083C}\\u{1083F}-\\u{10855}\\u{10860}-\\u{10876}\\u{10880}-\\u{1089E}\\u{108E0}-\\u{108F2}\\u{108F4}\\u{108F5}\\u{10900}-\\u{10915}\\u{10920}-\\u{10939}\\u{10940}-\\u{10959}\\u{10980}-\\u{109B7}\\u{109BE}\\u{109BF}\\u{10A00}\\u{10A10}-\\u{10A13}\\u{10A15}-\\u{10A17}\\u{10A19}-\\u{10A35}\\u{10A60}-\\u{10A7C}\\u{10A80}-\\u{10A9C}\\u{10AC0}-\\u{10AC7}\\u{10AC9}-\\u{10AE4}\\u{10B00}-\\u{10B35}\\u{10B40}-\\u{10B55}\\u{10B60}-\\u{10B72}\\u{10B80}-\\u{10B91}\\u{10C00}-\\u{10C48}\\u{10C80}-\\u{10CB2}\\u{10CC0}-\\u{10CF2}\\u{10D00}-\\u{10D23}\\u{10D4A}-\\u{10D65}\\u{10D6F}-\\u{10D85}\\u{10E80}-\\u{10EA9}\\u{10EB0}\\u{10EB1}\\u{10EC2}-\\u{10EC7}\\u{10F00}-\\u{10F1C}\\u{10F27}\\u{10F30}-\\u{10F45}\\u{10F70}-\\u{10F81}\\u{10FB0}-\\u{10FC4}\\u{10FE0}-\\u{10FF6}\\u{11003}-\\u{11037}\\u{11071}\\u{11072}\\u{11075}\\u{11083}-\\u{110AF}\\u{110D0}-\\u{110E8}\\u{11103}-\\u{11126}\\u{11144}\\u{11147}\\u{11150}-\\u{11172}\\u{11176}\\u{11183}-\\u{111B2}\\u{111C1}-\\u{111C4}\\u{111DA}\\u{111DC}\\u{11200}-\\u{11211}\\u{11213}-\\u{1122B}\\u{1123F}\\u{11240}\\u{11280}-\\u{11286}\\u{11288}\\u{1128A}-\\u{1128D}\\u{1128F}-\\u{1129D}\\u{1129F}-\\u{112A8}\\u{112B0}-\\u{112DE}\\u{11305}-\\u{1130C}\\u{1130F}\\u{11310}\\u{11313}-\\u{11328}\\u{1132A}-\\u{11330}\\u{11332}\\u{11333}\\u{11335}-\\u{11339}\\u{1133D}\\u{11350}\\u{1135D}-\\u{11361}\\u{11380}-\\u{11389}\\u{1138B}\\u{1138E}\\u{11390}-\\u{113B5}\\u{113B7}\\u{113D1}\\u{113D3}\\u{11400}-\\u{11434}\\u{11447}-\\u{1144A}\\u{1145F}-\\u{11461}\\u{11480}-\\u{114AF}\\u{114C4}\\u{114C5}\\u{114C7}\\u{11580}-\\u{115AE}\\u{115D8}-\\u{115DB}\\u{11600}-\\u{1162F}\\u{11644}\\u{11680}-\\u{116AA}\\u{116B8}\\u{11700}-\\u{1171A}\\u{11740}-\\u{11746}\\u{11800}-\\u{1182B}\\u{118A0}-\\u{118DF}\\u{118FF}-\\u{11906}\\u{11909}\\u{1190C}-\\u{11913}\\u{11915}\\u{11916}\\u{11918}-\\u{1192F}\\u{1193F}\\u{11941}\\u{119A0}-\\u{119A7}\\u{119AA}-\\u{119D0}\\u{119E1}\\u{119E3}\\u{11A00}\\u{11A0B}-\\u{11A32}\\u{11A3A}\\u{11A50}\\u{11A5C}-\\u{11A89}\\u{11A9D}\\u{11AB0}-\\u{11AF8}\\u{11BC0}-\\u{11BE0}\\u{11C00}-\\u{11C08}\\u{11C0A}-\\u{11C2E}\\u{11C40}\\u{11C72}-\\u{11C8F}\\u{11D00}-\\u{11D06}\\u{11D08}\\u{11D09}\\u{11D0B}-\\u{11D30}\\u{11D46}\\u{11D60}-\\u{11D65}\\u{11D67}\\u{11D68}\\u{11D6A}-\\u{11D89}\\u{11D98}\\u{11DB0}-\\u{11DDB}\\u{11EE0}-\\u{11EF2}\\u{11F02}\\u{11F04}-\\u{11F10}\\u{11F12}-\\u{11F33}\\u{11FB0}\\u{12000}-\\u{12399}\\u{12480}-\\u{12543}\\u{12F90}-\\u{12FF0}\\u{13000}-\\u{1342F}\\u{13441}-\\u{13446}\\u{13460}-\\u{143FA}\\u{14400}-\\u{14646}\\u{16100}-\\u{1611D}\\u{16800}-\\u{16A38}\\u{16A40}-\\u{16A5E}\\u{16A70}-\\u{16ABE}\\u{16AD0}-\\u{16AED}\\u{16B00}-\\u{16B2F}\\u{16B40}-\\u{16B43}\\u{16B63}-\\u{16B77}\\u{16B7D}-\\u{16B8F}\\u{16D40}-\\u{16D6C}\\u{16E40}-\\u{16E7F}\\u{16EA0}-\\u{16EB8}\\u{16EBB}-\\u{16ED3}\\u{16F00}-\\u{16F4A}\\u{16F50}\\u{16F93}-\\u{16F9F}\\u{16FE0}\\u{16FE1}\\u{16FE3}\\u{16FF2}\\u{16FF3}\\u{17000}-\\u{18CD5}\\u{18CFF}-\\u{18D1E}\\u{18D80}-\\u{18DF2}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1B170}-\\u{1B2FB}\\u{1BC00}-\\u{1BC6A}\\u{1BC70}-\\u{1BC7C}\\u{1BC80}-\\u{1BC88}\\u{1BC90}-\\u{1BC99}\\u{1D400}-\\u{1D454}\\u{1D456}-\\u{1D49C}\\u{1D49E}\\u{1D49F}\\u{1D4A2}\\u{1D4A5}\\u{1D4A6}\\u{1D4A9}-\\u{1D4AC}\\u{1D4AE}-\\u{1D4B9}\\u{1D4BB}\\u{1D4BD}-\\u{1D4C3}\\u{1D4C5}-\\u{1D505}\\u{1D507}-\\u{1D50A}\\u{1D50D}-\\u{1D514}\\u{1D516}-\\u{1D51C}\\u{1D51E}-\\u{1D539}\\u{1D53B}-\\u{1D53E}\\u{1D540}-\\u{1D544}\\u{1D546}\\u{1D54A}-\\u{1D550}\\u{1D552}-\\u{1D6A5}\\u{1D6A8}-\\u{1D6C0}\\u{1D6C2}-\\u{1D6DA}\\u{1D6DC}-\\u{1D6FA}\\u{1D6FC}-\\u{1D714}\\u{1D716}-\\u{1D734}\\u{1D736}-\\u{1D74E}\\u{1D750}-\\u{1D76E}\\u{1D770}-\\u{1D788}\\u{1D78A}-\\u{1D7A8}\\u{1D7AA}-\\u{1D7C2}\\u{1D7C4}-\\u{1D7CB}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E100}-\\u{1E12C}\\u{1E137}-\\u{1E13D}\\u{1E14E}\\u{1E290}-\\u{1E2AD}\\u{1E2C0}-\\u{1E2EB}\\u{1E4D0}-\\u{1E4EB}\\u{1E5D0}-\\u{1E5ED}\\u{1E5F0}\\u{1E6C0}-\\u{1E6DE}\\u{1E6E0}-\\u{1E6E2}\\u{1E6E4}\\u{1E6E5}\\u{1E6E7}-\\u{1E6ED}\\u{1E6F0}-\\u{1E6F4}\\u{1E6FE}\\u{1E6FF}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1E800}-\\u{1E8C4}\\u{1E900}-\\u{1E943}\\u{1E94B}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}';
59
+ exports.DISPLAY_NAME_DENIED_SYMBOL_LETTERS_RANGES = '\\u{534D}\\u{5350}';
60
+ exports.DISPLAY_NAME_NAME_SEPARATORS_RANGES = '\\u{B7}\\u{5BE}\\u{F0B}\\u{30FB}';
@@ -3,7 +3,7 @@
3
3
  * Validation utilities for common data validation patterns
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.PASSWORD_REGEX = exports.USERNAME_REGEX = exports.EMAIL_REGEX = void 0;
6
+ exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE = exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.PASSWORD_REGEX = exports.USERNAME_REGEX = exports.EMAIL_REGEX = exports.MAX_DISPLAY_NAME_LENGTH = void 0;
7
7
  exports.isValidEmail = isValidEmail;
8
8
  exports.isValidUsername = isValidUsername;
9
9
  exports.isValidPassword = isValidPassword;
@@ -23,6 +23,11 @@ exports.sanitizeHTML = sanitizeHTML;
23
23
  exports.isValidObjectId = isValidObjectId;
24
24
  exports.validateAndSanitizeUserInput = validateAndSanitizeUserInput;
25
25
  const displayNamePolicyRanges_generated_1 = require("./displayNamePolicyRanges.generated");
26
+ /**
27
+ * Maximum stored length of a display name, in code units after cleaning.
28
+ * Shared by the API write path and client input surfaces.
29
+ */
30
+ exports.MAX_DISPLAY_NAME_LENGTH = 80;
26
31
  /**
27
32
  * Email validation regex
28
33
  */
@@ -69,7 +74,16 @@ function isValidPassword(password) {
69
74
  * ideographic space, …) — but NOT control whitespace such as tab, newline,
70
75
  * or carriage return, which would break layout or enable multi-line
71
76
  * spoofing,
72
- * - the straight apostrophe (`'`, e.g. "O'Brien").
77
+ * - the straight apostrophe (`'`, e.g. "O'Brien"),
78
+ * - four name SEPARATORS — `·` U+00B7, `־` U+05BE, `་` U+0F0B, `・` U+30FB —
79
+ * but ONLY directly between two letters (`Codeur·euses`, `お坐・エガード`,
80
+ * `אברמסקי־קרוננברג`, `འོད་ཟེར`). Every one is General_Category P, so the
81
+ * letters intersection strips them by default; they are re-admitted because
82
+ * stripping them SPLITS a real name in two. The flanking condition is not a
83
+ * refinement but the whole point: the same characters are also used as
84
+ * ornament (a trailing `Roberto ·`), and unconditional admission would let
85
+ * that through. See {@link DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE}. The
86
+ * ASCII hyphen is NOT among them — `Jean-Luc` stays rejected.
73
87
  *
74
88
  * Everything else is rejected: emoji (🐧), symbols (⁂ ⏚), `:emoji:` shortcodes,
75
89
  * digits, hyphens, dots, control whitespace (tab/newline/CR), letters from
@@ -79,7 +93,15 @@ function isValidPassword(password) {
79
93
  *
80
94
  * The allowlist is expressed with Unicode Script_Extensions (scx=…) so a letter
81
95
  * shared by several scripts (e.g. a Han ideograph used in both Chinese and
82
- * Japanese) still matches. It is the set of scripts Unicode UTS #39 marks
96
+ * Japanese) still matches, INTERSECTED with General_Category L so only the
97
+ * scripts' LETTERS are admitted. That intersection is load-bearing, not a
98
+ * refinement: `scx=X` also carries script X's own digits, punctuation and
99
+ * symbols, so the un-intersected allowlist admitted 1831 non-letter code points
100
+ * — script digits (`٠١٢`, `०१२`), 1082 symbols (`֍ ۞ ৳`), 180 punctuation marks
101
+ * (`։ ، ؛ ।`), and 9 INVISIBLE format/control characters, among them U+061C
102
+ * ARABIC LETTER MARK (a bidi control that can visually reorder a name) and
103
+ * U+180E MONGOLIAN VOWEL SEPARATOR. Without it the rejections listed above held
104
+ * for ASCII input only. It is the set of scripts Unicode UTS #39 marks
83
105
  * "Recommended" for general interchange / identifiers, plus Cherokee and
84
106
  * Mongolian (both in real modern name use). "Common" script is deliberately
85
107
  * EXCLUDED — that is where ASCII digits and general punctuation live, and this
@@ -87,6 +109,29 @@ function isValidPassword(password) {
87
109
  * name needs are added back explicitly. Limited-use / excluded / historic
88
110
  * scripts (Batak, Runic, Deseret, Adlam, …) are simply absent.
89
111
  *
112
+ * CODE-POINT DENYLIST — a character policy classifies FORM, never MEANING, so a
113
+ * code point can be a perfectly ordinary letter to Unicode and a hate symbol to
114
+ * a reader. `卐` U+5350 and `卍` U+534D are the case in point: both are CJK
115
+ * Unified Ideographs (General_Category Lo, Script_Extensions Han), i.e. the same
116
+ * kind of thing as `山` in `山田太郎`, so NO script-level or category-level rule
117
+ * can separate them — every rule that would exclude these two also excludes Han
118
+ * itself, rejecting every real Chinese, Japanese and Korean name. They are
119
+ * therefore enumerated and SUBTRACTED from the allowlist at generation time (see
120
+ * `SYMBOL_LETTER_DENYLIST` in `scripts/generateDisplayNamePolicyRanges.mjs`).
121
+ * Because the subtraction happens inside the one emitted allowlist, every
122
+ * consumer enforces it with no extra probe and none can forget it; the generator
123
+ * additionally REFUSES an entry that an existing lever already excludes (e.g.
124
+ * the Tibetan svasti signs U+0FD5–U+0FD8, General_Category So, already dropped
125
+ * by the intersection above), so the list cannot silently accumulate dead
126
+ * weight.
127
+ *
128
+ * REMAINING LIMIT — that closes the "letter that reads as a symbol" gap, not the
129
+ * other one: slurs and abusive phrasing spelled in ordinary allowlisted letters
130
+ * pass by construction, because they are built from exactly the characters every
131
+ * real name needs. No character-level rule — allowlist, intersection, or
132
+ * denylist — can reject them; that needs a word-level moderation layer, which is
133
+ * deliberately not attempted here.
134
+ *
90
135
  * HERMES / RANGES: the class bodies below are built from explicit Unicode
91
136
  * code-point RANGES ({@link DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES} et al. from
92
137
  * `./displayNamePolicyRanges.generated`), NOT from `scx`/General_Category
@@ -107,20 +152,27 @@ function isValidPassword(password) {
107
152
  */
108
153
  /**
109
154
  * The curated allowlist of Unicode scripts permitted in a display name, as a
110
- * character-class body of explicit code-point ranges (the compressed union of
111
- * the 30 allowlisted Script_Extensions, generated on V8). Interpolated into the
112
- * negated class below.
155
+ * character-class body of explicit code-point ranges: the union of the 30
156
+ * allowlisted Script_Extensions, INTERSECTED with General_Category L (so letters
157
+ * only), MINUS the symbol-letter denylist — 120823 code points. Interpolated
158
+ * into the negated class below, which is why both the reject gate here and the
159
+ * `@oxyhq/api` strip path inherit the denylist without a second pattern.
113
160
  */
114
161
  exports.DISPLAY_NAME_ALLOWED_SCRIPTS = displayNamePolicyRanges_generated_1.DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES;
115
162
  /**
116
163
  * Source of the disallowed-character pattern: the negation of the full allowed
117
164
  * set (allowlisted scripts + combining marks + space separators + the straight
118
- * apostrophe). Consumers compile this with the `u` flag (and `g` for a global
119
- * strip). The whitespace class is space separators only (General_Category Zs),
120
- * NOT `\s` — the latter would admit tab/newline/carriage return, which break
121
- * layout and enable multi-line spoofing.
165
+ * apostrophe + the name separators). Consumers compile this with the `u` flag
166
+ * (and `g` for a global strip). The whitespace class is space separators only
167
+ * (General_Category Zs), NOT `\s` — the latter would admit tab/newline/carriage
168
+ * return, which break layout and enable multi-line spoofing.
169
+ *
170
+ * The name separators are admitted here only as CHARACTERS. Their position rule
171
+ * is a separate pattern ({@link DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE}), for
172
+ * the same reason combining marks are: a negated character class cannot express
173
+ * "allowed only in this context". Both halves must be applied together.
122
174
  */
123
- exports.DISPLAY_NAME_DISALLOWED_SOURCE = `[^${exports.DISPLAY_NAME_ALLOWED_SCRIPTS}${displayNamePolicyRanges_generated_1.DISPLAY_NAME_COMBINING_MARKS_RANGES}${displayNamePolicyRanges_generated_1.DISPLAY_NAME_SPACE_SEPARATORS_RANGES}']`;
175
+ exports.DISPLAY_NAME_DISALLOWED_SOURCE = `[^${exports.DISPLAY_NAME_ALLOWED_SCRIPTS}${displayNamePolicyRanges_generated_1.DISPLAY_NAME_COMBINING_MARKS_RANGES}${displayNamePolicyRanges_generated_1.DISPLAY_NAME_SPACE_SEPARATORS_RANGES}${displayNamePolicyRanges_generated_1.DISPLAY_NAME_NAME_SEPARATORS_RANGES}']`;
124
176
  /**
125
177
  * Source of the orphaned combining-mark pattern: a run of combining marks NOT
126
178
  * attached to a base letter (preceded by string start, whitespace, the
@@ -133,26 +185,63 @@ exports.DISPLAY_NAME_DISALLOWED_SOURCE = `[^${exports.DISPLAY_NAME_ALLOWED_SCRIP
133
185
  * an allowlisted base letter is preserved.
134
186
  */
135
187
  exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = `(?<![${displayNamePolicyRanges_generated_1.DISPLAY_NAME_LETTERS_RANGES}${displayNamePolicyRanges_generated_1.DISPLAY_NAME_COMBINING_MARKS_RANGES}])[${displayNamePolicyRanges_generated_1.DISPLAY_NAME_COMBINING_MARKS_RANGES}]+`;
188
+ /**
189
+ * Source of the unflanked name-separator pattern — the positional half of the
190
+ * name-separator rule, and the exact counterpart of
191
+ * {@link DISPLAY_NAME_ORPHANED_MARK_SOURCE}: a combining mark is allowed only
192
+ * when it rides a base letter, and a name separator is allowed only when it JOINS
193
+ * two letters. Matches a separator that is missing a letter on either side, so
194
+ * consumers can reject it (non-global probe) or strip it (`g` flag).
195
+ *
196
+ * Two alternatives, one per side, because JS has no "not surrounded by" atom:
197
+ * - `(?<![letters][marks])[sep]` — nothing letter-like immediately BEFORE.
198
+ * - `[sep](?![letters])` — no letter immediately AFTER.
199
+ *
200
+ * The left-hand class deliberately includes combining marks as well as letters:
201
+ * a base letter can carry an accent (`Renée·euses`, or a decomposed `e`+◌́), and
202
+ * that mark sits between the letter and the separator. Treating a mark as
203
+ * letter-like is what stops an accent from defeating the flanking test — the
204
+ * same reason the orphaned-mark lookbehind uses the identical pair of classes.
205
+ * The right-hand class is letters only: a mark AFTER a separator has no base and
206
+ * is removed by the orphaned-mark rule, so the separator is genuinely unflanked.
207
+ *
208
+ * Both lookarounds are single-character (no variable-length lookbehind), and the
209
+ * classes are explicit code-point ranges, so the compiled regex is within what
210
+ * Hermes accepts.
211
+ *
212
+ * `Codeur·euses` and `お坐・エガード` match NOTHING here and survive. A leading
213
+ * `·Roberto`, a trailing `Roberto ·`, and a doubled `a··b` each match and are
214
+ * stripped — which is what keeps a decorative middle dot from riding in on the
215
+ * back of the orthographic one.
216
+ */
217
+ exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE = `(?<![${displayNamePolicyRanges_generated_1.DISPLAY_NAME_LETTERS_RANGES}${displayNamePolicyRanges_generated_1.DISPLAY_NAME_COMBINING_MARKS_RANGES}])[${displayNamePolicyRanges_generated_1.DISPLAY_NAME_NAME_SEPARATORS_RANGES}]|[${displayNamePolicyRanges_generated_1.DISPLAY_NAME_NAME_SEPARATORS_RANGES}](?![${displayNamePolicyRanges_generated_1.DISPLAY_NAME_LETTERS_RANGES}])`;
136
218
  /** Non-global probe for the presence of a disallowed character. */
137
219
  const DISALLOWED_PROBE = new RegExp(exports.DISPLAY_NAME_DISALLOWED_SOURCE, 'u');
138
220
  /** Non-global probe for the presence of an orphaned combining mark. */
139
221
  const ORPHANED_MARK_PROBE = new RegExp(exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE, 'u');
222
+ /** Non-global probe for the presence of an unflanked name separator. */
223
+ const UNFLANKED_SEPARATOR_PROBE = new RegExp(exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE, 'u');
140
224
  /**
141
225
  * Whether `raw` already satisfies the display-name policy, i.e. it contains no
142
- * disallowed characters AND no orphaned combining marks. Used to REJECT native
143
- * (signup / profile edit) names with a 400 rather than silently stripping them,
144
- * and to validate inline in the client editor.
226
+ * disallowed characters, no orphaned combining marks, and no unflanked name
227
+ * separator. Used to REJECT native (signup / profile edit) names with a 400
228
+ * rather than silently stripping them, and to validate inline in the client
229
+ * editor.
145
230
  *
146
- * The orphaned-mark probe runs on the NFC-normalized form so a legitimate
147
- * decomposed accent (`e`+◌́) which normalization recomposes into `é` is NOT
148
- * rejected, while a lone, base-less mark (e.g. `"༘"`) IS.
231
+ * The two positional probes run on the NFC-normalized form, the character probe
232
+ * on the raw input. Normalization matters for both: a legitimate decomposed
233
+ * accent (`e`+◌́) recomposes into `é`, so it is NOT rejected as an orphaned mark,
234
+ * and a separator after that accent sees a base letter rather than a mark.
149
235
  *
150
- * The function only checks the character set; an empty or whitespace-only string
151
- * is considered valid (`true`). Call sites that require a non-empty name enforce
152
- * that separately.
236
+ * The function only checks the character set and separator placement; an empty
237
+ * or whitespace-only string is considered valid (`true`). Call sites that require
238
+ * a non-empty name enforce that separately.
153
239
  */
154
240
  function isValidDisplayName(raw) {
155
- return (!DISALLOWED_PROBE.test(raw) && !ORPHANED_MARK_PROBE.test(raw.normalize('NFC')));
241
+ const normalized = raw.normalize('NFC');
242
+ return (!DISALLOWED_PROBE.test(raw) &&
243
+ !ORPHANED_MARK_PROBE.test(normalized) &&
244
+ !UNFLANKED_SEPARATOR_PROBE.test(normalized));
156
245
  }
157
246
  /**
158
247
  * Validate required string