@adaptic/utils 0.0.977 → 0.0.978

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
@@ -5604,6 +5604,92 @@ const DEFAULT_RETRY_CONFIG = {
5604
5604
  retryableStatusCodes: [429, 500, 502, 503, 504],
5605
5605
  retryOnNetworkError: true,
5606
5606
  };
5607
+ /**
5608
+ * Node.js / undici / system error codes that represent transient network
5609
+ * conditions. Present on `error.code` for net/http/dns/undici errors.
5610
+ */
5611
+ const RETRYABLE_ERROR_CODES = new Set([
5612
+ "ETIMEDOUT",
5613
+ "ESOCKETTIMEDOUT",
5614
+ "ECONNRESET",
5615
+ "ECONNREFUSED",
5616
+ "EHOSTUNREACH",
5617
+ "ENETUNREACH",
5618
+ "EAI_AGAIN",
5619
+ "EPIPE",
5620
+ "ECONNABORTED",
5621
+ "ENOTFOUND",
5622
+ "UND_ERR_CONNECT_TIMEOUT",
5623
+ "UND_ERR_HEADERS_TIMEOUT",
5624
+ "UND_ERR_BODY_TIMEOUT",
5625
+ "UND_ERR_SOCKET",
5626
+ "UND_ERR_CLOSED",
5627
+ "UND_ERR_REQ_CONTENT_LENGTH_MISMATCH",
5628
+ ]);
5629
+ /**
5630
+ * Error constructor names / `error.name` values that indicate transient
5631
+ * abort / timeout conditions.
5632
+ */
5633
+ const RETRYABLE_ERROR_NAMES = new Set([
5634
+ "AbortError",
5635
+ "TimeoutError",
5636
+ "FetchError",
5637
+ "RequestTimeoutError",
5638
+ "ConnectTimeoutError",
5639
+ "HeadersTimeoutError",
5640
+ "BodyTimeoutError",
5641
+ ]);
5642
+ /**
5643
+ * Message-pattern fallback for libraries that discard error codes/names but
5644
+ * preserve text (e.g., some Apollo/axios wrappers).
5645
+ */
5646
+ const RETRYABLE_MESSAGE_PATTERNS = [
5647
+ /aborted/i,
5648
+ /timeout/i,
5649
+ /timed out/i,
5650
+ /network error/i,
5651
+ /socket hang up/i,
5652
+ /connection (reset|refused|closed)/i,
5653
+ /ECONNRESET/,
5654
+ /ETIMEDOUT/,
5655
+ /ECONNREFUSED/,
5656
+ /EAI_AGAIN/,
5657
+ /UND_ERR_/,
5658
+ ];
5659
+ /**
5660
+ * Walks the `error.cause` chain (capped to avoid cycles) and tests whether
5661
+ * any link along the chain looks like a transient network error. Modern APIs
5662
+ * (undici, fetch, Apollo Client 3.8+) wrap the root network failure as a
5663
+ * `.cause`, so the surface `Error` may report a generic message while the
5664
+ * actionable signal lives one or more levels deeper.
5665
+ */
5666
+ function isTransientNetworkError(error) {
5667
+ const MAX_CAUSE_DEPTH = 6;
5668
+ let current = error;
5669
+ for (let depth = 0; depth < MAX_CAUSE_DEPTH && current; depth++) {
5670
+ if (current instanceof Error || typeof current === "object") {
5671
+ const err = current;
5672
+ if (typeof err.name === "string" && RETRYABLE_ERROR_NAMES.has(err.name)) {
5673
+ return true;
5674
+ }
5675
+ if (typeof err.code === "string" && RETRYABLE_ERROR_CODES.has(err.code)) {
5676
+ return true;
5677
+ }
5678
+ if (typeof err.message === "string") {
5679
+ for (const pattern of RETRYABLE_MESSAGE_PATTERNS) {
5680
+ if (pattern.test(err.message)) {
5681
+ return true;
5682
+ }
5683
+ }
5684
+ }
5685
+ current = err.cause;
5686
+ }
5687
+ else {
5688
+ break;
5689
+ }
5690
+ }
5691
+ return false;
5692
+ }
5607
5693
  /**
5608
5694
  * Analyzes an error and determines if it's retryable.
5609
5695
  * @param error - The error to analyze
@@ -5668,6 +5754,19 @@ function analyzeError(error, response, config) {
5668
5754
  isRetryable: config.retryOnNetworkError,
5669
5755
  };
5670
5756
  }
5757
+ // Handle transient network conditions: AbortError, TimeoutError,
5758
+ // Node/undici error codes (ETIMEDOUT, ECONNRESET, UND_ERR_*), and
5759
+ // wrapped failures exposed via error.cause. This catches the broad class
5760
+ // of infrastructure flakes that the TypeError-only check above misses.
5761
+ if (isTransientNetworkError(error)) {
5762
+ const reason = error instanceof Error ? error.message : "Transient network error";
5763
+ return {
5764
+ type: "NETWORK_ERROR",
5765
+ reason,
5766
+ status: null,
5767
+ isRetryable: config.retryOnNetworkError,
5768
+ };
5769
+ }
5671
5770
  // Handle error objects with messages
5672
5771
  if (error instanceof Error) {
5673
5772
  // Parse error messages that might contain status information