@openzeppelin/ui-utils 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1425,7 +1425,7 @@ function simpleHash(str) {
1425
1425
  * ```
1426
1426
  */
1427
1427
  function validateBytes(value, options = {}) {
1428
- const { acceptedFormats = "both", maxBytes, allowHexPrefix = true } = options;
1428
+ const { acceptedFormats = "both", maxBytes, exactBytes, allowHexPrefix = true } = options;
1429
1429
  if (!value || value.trim() === "") return {
1430
1430
  isValid: true,
1431
1431
  cleanedValue: "",
@@ -1487,6 +1487,13 @@ function validateBytes(value, options = {}) {
1487
1487
  cleanedValue: cleanValue,
1488
1488
  detectedFormat
1489
1489
  };
1490
+ if (exactBytes && byteSize !== exactBytes) return {
1491
+ isValid: false,
1492
+ error: `Exactly ${exactBytes} bytes required (${detectedFormat === "hex" ? `${exactBytes * 2} hex characters` : `${exactBytes} bytes`}), got ${byteSize} bytes`,
1493
+ cleanedValue: cleanValue,
1494
+ detectedFormat,
1495
+ byteSize
1496
+ };
1490
1497
  if (maxBytes && byteSize > maxBytes) return {
1491
1498
  isValid: false,
1492
1499
  error: `Maximum ${maxBytes} bytes allowed (${detectedFormat === "hex" ? `${maxBytes * 2} hex characters` : `${maxBytes} bytes`})`,
@@ -2256,14 +2263,204 @@ function getWalletNetworkSwitcherVariantClassName(variant) {
2256
2263
  }
2257
2264
  }
2258
2265
 
2266
+ //#endregion
2267
+ //#region src/serviceErrorDetection.ts
2268
+ /**
2269
+ * Utilities for detecting and categorizing network service connection errors.
2270
+ * This module provides functions to identify when errors are caused by network
2271
+ * service failures (RPC, Explorer, Indexer, etc.) and determine which service
2272
+ * type was affected.
2273
+ */
2274
+ /**
2275
+ * Common patterns that indicate a network service connection failure.
2276
+ * These patterns help distinguish network/service issues from other errors.
2277
+ */
2278
+ const SERVICE_ERROR_PATTERNS = [
2279
+ "failed to fetch",
2280
+ "network error",
2281
+ "connection refused",
2282
+ "timeout",
2283
+ "econnrefused",
2284
+ "fetch failed",
2285
+ "network request failed",
2286
+ "connection timeout",
2287
+ "unable to connect",
2288
+ "no response",
2289
+ "service unavailable",
2290
+ "could not connect",
2291
+ "connection failed",
2292
+ "network unavailable",
2293
+ "dns resolution failed",
2294
+ "socket hang up",
2295
+ "read econnreset",
2296
+ "503",
2297
+ "502",
2298
+ "504",
2299
+ "500",
2300
+ "gateway timeout",
2301
+ "bad gateway",
2302
+ "internal server error",
2303
+ "rpc error",
2304
+ "rpc endpoint",
2305
+ "indexer",
2306
+ "explorer",
2307
+ "horizon",
2308
+ "api error",
2309
+ "rate limit",
2310
+ "too many requests",
2311
+ "429"
2312
+ ];
2313
+ /**
2314
+ * Known network service types with their display names.
2315
+ * Adapters can use any service ID, but these are common ones.
2316
+ */
2317
+ const SERVICE_DISPLAY_NAMES = {
2318
+ rpc: "RPC Provider",
2319
+ explorer: "Block Explorer",
2320
+ indexer: "Indexer",
2321
+ horizon: "Horizon API",
2322
+ "contract-definitions": "Contract Definitions",
2323
+ soroban: "Soroban RPC",
2324
+ graphql: "GraphQL API",
2325
+ "proof-server": "Proof Server",
2326
+ node: "Node Provider"
2327
+ };
2328
+ /**
2329
+ * Patterns that suggest a specific service type caused the error.
2330
+ * More specific patterns take priority in the detection order.
2331
+ */
2332
+ const SERVICE_TYPE_HINTS = [
2333
+ {
2334
+ patterns: [
2335
+ "indexer",
2336
+ "graphql",
2337
+ "subquery",
2338
+ "subgraph",
2339
+ "the graph"
2340
+ ],
2341
+ serviceType: "indexer"
2342
+ },
2343
+ {
2344
+ patterns: [
2345
+ "explorer",
2346
+ "etherscan",
2347
+ "blockscout",
2348
+ "sourcify",
2349
+ "polygonscan",
2350
+ "bscscan"
2351
+ ],
2352
+ serviceType: "explorer"
2353
+ },
2354
+ {
2355
+ patterns: ["horizon", "stellar"],
2356
+ serviceType: "horizon"
2357
+ },
2358
+ {
2359
+ patterns: ["soroban"],
2360
+ serviceType: "soroban"
2361
+ },
2362
+ {
2363
+ patterns: [
2364
+ "rpc",
2365
+ "jsonrpc",
2366
+ "json-rpc",
2367
+ "eth_",
2368
+ "web3",
2369
+ "provider",
2370
+ "node"
2371
+ ],
2372
+ serviceType: "rpc"
2373
+ }
2374
+ ];
2375
+ /**
2376
+ * Checks if an error message indicates a network service connection failure.
2377
+ *
2378
+ * @param errorMessage The error message to check
2379
+ * @returns True if the error appears to be caused by a service connection issue
2380
+ *
2381
+ * @example
2382
+ * ```ts
2383
+ * isServiceConnectionError('Failed to fetch'); // true
2384
+ * isServiceConnectionError('Invalid address'); // false
2385
+ * ```
2386
+ */
2387
+ function isServiceConnectionError(errorMessage) {
2388
+ if (!errorMessage) return false;
2389
+ const lowerCaseError = errorMessage.toLowerCase();
2390
+ return SERVICE_ERROR_PATTERNS.some((pattern) => lowerCaseError.includes(pattern));
2391
+ }
2392
+ /**
2393
+ * Attempts to determine which service type caused the error based on the error message.
2394
+ * Falls back to 'rpc' as the most common case for blockchain-related failures.
2395
+ *
2396
+ * @param errorMessage The error message to analyze
2397
+ * @returns The detected service type (e.g., 'rpc', 'explorer', 'indexer')
2398
+ *
2399
+ * @example
2400
+ * ```ts
2401
+ * detectServiceType('Indexer connection failed'); // 'indexer'
2402
+ * detectServiceType('Etherscan API error'); // 'explorer'
2403
+ * detectServiceType('RPC endpoint timeout'); // 'rpc'
2404
+ * detectServiceType('Unknown error'); // 'rpc' (default)
2405
+ * ```
2406
+ */
2407
+ function detectServiceType(errorMessage) {
2408
+ if (!errorMessage) return "rpc";
2409
+ const lowerCaseError = errorMessage.toLowerCase();
2410
+ for (const { patterns, serviceType } of SERVICE_TYPE_HINTS) if (patterns.some((pattern) => lowerCaseError.includes(pattern))) return serviceType;
2411
+ return "rpc";
2412
+ }
2413
+ /**
2414
+ * Gets a user-friendly display name for a service type.
2415
+ * Falls back to capitalizing the service ID if not found in known mappings.
2416
+ *
2417
+ * @param serviceType The service type identifier (e.g., 'rpc', 'explorer')
2418
+ * @returns A user-friendly display name (e.g., 'RPC Provider', 'Block Explorer')
2419
+ *
2420
+ * @example
2421
+ * ```ts
2422
+ * getServiceDisplayName('rpc'); // 'RPC Provider'
2423
+ * getServiceDisplayName('indexer'); // 'Indexer'
2424
+ * getServiceDisplayName('custom-service'); // 'Custom service'
2425
+ * ```
2426
+ */
2427
+ function getServiceDisplayName(serviceType) {
2428
+ return SERVICE_DISPLAY_NAMES[serviceType] || serviceType.charAt(0).toUpperCase() + serviceType.slice(1).replace(/-/g, " ");
2429
+ }
2430
+ /**
2431
+ * Analyzes an error and returns detailed information about the service failure.
2432
+ *
2433
+ * @param errorMessage The error message to analyze
2434
+ * @returns Object containing detection results
2435
+ *
2436
+ * @example
2437
+ * ```ts
2438
+ * const result = analyzeServiceError('Indexer timeout');
2439
+ * // { isServiceError: true, serviceType: 'indexer', serviceName: 'Indexer' }
2440
+ * ```
2441
+ */
2442
+ function analyzeServiceError(errorMessage) {
2443
+ const isServiceError = isServiceConnectionError(errorMessage);
2444
+ const serviceType = detectServiceType(errorMessage);
2445
+ return {
2446
+ isServiceError,
2447
+ serviceType,
2448
+ serviceName: getServiceDisplayName(serviceType)
2449
+ };
2450
+ }
2451
+
2259
2452
  //#endregion
2260
2453
  exports.AnalyticsService = AnalyticsService;
2261
2454
  exports.AppConfigService = AppConfigService;
2262
2455
  exports.DEFAULT_CONCURRENCY_LIMIT = DEFAULT_CONCURRENCY_LIMIT;
2456
+ exports.SERVICE_DISPLAY_NAMES = SERVICE_DISPLAY_NAMES;
2457
+ exports.SERVICE_ERROR_PATTERNS = SERVICE_ERROR_PATTERNS;
2458
+ exports.SERVICE_TYPE_HINTS = SERVICE_TYPE_HINTS;
2263
2459
  exports.UserExplorerConfigService = UserExplorerConfigService;
2264
2460
  exports.UserNetworkServiceConfigService = UserNetworkServiceConfigService;
2265
2461
  exports.UserRpcConfigService = UserRpcConfigService;
2266
2462
  exports.addressesEqual = addressesEqual;
2463
+ exports.analyzeServiceError = analyzeServiceError;
2267
2464
  exports.appConfigService = appConfigService;
2268
2465
  exports.base64ToBytes = base64ToBytes;
2269
2466
  exports.buildRequiredInputSnapshot = buildRequiredInputSnapshot;
@@ -2275,6 +2472,7 @@ exports.createEmptySnapshot = createEmptySnapshot;
2275
2472
  exports.delay = delay;
2276
2473
  exports.deserializeSnapshot = deserializeSnapshot;
2277
2474
  exports.detectBytesEncoding = detectBytesEncoding;
2475
+ exports.detectServiceType = detectServiceType;
2278
2476
  exports.enhanceNumericValidation = enhanceNumericValidation;
2279
2477
  exports.findRoleAssignment = findRoleAssignment;
2280
2478
  exports.formatAccessControlError = formatAccessControlError;
@@ -2287,6 +2485,7 @@ exports.getErrorMessage = getErrorMessage;
2287
2485
  exports.getForcedService = getForcedService;
2288
2486
  exports.getInvalidUrlMessage = getInvalidUrlMessage;
2289
2487
  exports.getMissingRequiredContractInputs = getMissingRequiredContractInputs;
2488
+ exports.getServiceDisplayName = getServiceDisplayName;
2290
2489
  exports.getTotalMemberCount = getTotalMemberCount;
2291
2490
  exports.getWalletAccountDisplaySizeProps = getWalletAccountDisplaySizeProps;
2292
2491
  exports.getWalletButtonSizeProps = getWalletButtonSizeProps;
@@ -2301,6 +2500,7 @@ exports.isDevelopmentOrTestEnvironment = isDevelopmentOrTestEnvironment;
2301
2500
  exports.isPlainObject = isPlainObject;
2302
2501
  exports.isProductionEnvironment = isProductionEnvironment;
2303
2502
  exports.isRecordWithProperties = isRecordWithProperties;
2503
+ exports.isServiceConnectionError = isServiceConnectionError;
2304
2504
  exports.isValidUrl = isValidUrl;
2305
2505
  exports.logger = logger;
2306
2506
  exports.normalizeAddress = normalizeAddress;