@openzeppelin/ui-utils 1.1.0 → 1.2.0

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