From eaa775d1e1f840618c5f457148d0361a45cb985f Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Thu, 26 Mar 2026 15:29:32 -0400 Subject: [PATCH 1/2] feat: read httpConfig from CDN integration settings and honor enabled flags - Read httpConfig from integrations["Segment.io"] in SegmentDestination.update(), falling back to top-level CDN config via analytics.getHttpConfig() - Add backoffEnabled parameter to classifyError() so that transient errors are classified as permanent when backoffConfig.enabled is false - Also handle rateLimitEnabled + statusCodeOverrides interaction when the relevant config is disabled - Add retry-settings test suite to e2e-config.json Co-Authored-By: Claude Opus 4.6 --- e2e-cli/e2e-config.json | 5 +++-- packages/core/src/errors.ts | 20 +++++++++++++++++-- .../core/src/plugins/SegmentDestination.ts | 19 +++++++++++++++++- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/e2e-cli/e2e-config.json b/e2e-cli/e2e-config.json index ac88545d2..a7417576d 100644 --- a/e2e-cli/e2e-config.json +++ b/e2e-cli/e2e-config.json @@ -1,9 +1,10 @@ { "sdk": "react-native", - "test_suites": "basic,settings,retry", + "test_suites": "basic,settings,retry,retry-settings", "auto_settings": true, "patch": null, "env": { - "BROWSER_BATCHING": "true" + "BROWSER_BATCHING": "true", + "HTTP_CONFIG_SETTINGS": "true" } } diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index c55fab691..f661778ea 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -147,11 +147,19 @@ export const classifyError = ( default5xxBehavior?: 'drop' | 'retry'; statusCodeOverrides?: Record; rateLimitEnabled?: boolean; + backoffEnabled?: boolean; } ): ErrorClassification => { const override = config?.statusCodeOverrides?.[statusCode.toString()]; if (override !== undefined) { if (override === 'retry') { + // If the relevant config is disabled, treat retry overrides as permanent + if (statusCode === 429 && config?.rateLimitEnabled === false) { + return new ErrorClassification('permanent'); + } + if (statusCode !== 429 && config?.backoffEnabled === false) { + return new ErrorClassification('permanent'); + } return statusCode === 429 ? new ErrorClassification('rate_limit') : new ErrorClassification('transient'); @@ -159,12 +167,17 @@ export const classifyError = ( return new ErrorClassification('permanent'); } - if (statusCode === 429 && config?.rateLimitEnabled !== false) { - return new ErrorClassification('rate_limit'); + if (statusCode === 429) { + return config?.rateLimitEnabled !== false + ? new ErrorClassification('rate_limit') + : new ErrorClassification('permanent'); } if (statusCode >= 400 && statusCode < 500) { const behavior = config?.default4xxBehavior ?? 'drop'; + if (behavior === 'retry' && config?.backoffEnabled === false) { + return new ErrorClassification('permanent'); + } return new ErrorClassification( behavior === 'retry' ? 'transient' : 'permanent' ); @@ -172,6 +185,9 @@ export const classifyError = ( if (statusCode >= 500 && statusCode < 600) { const behavior = config?.default5xxBehavior ?? 'retry'; + if (behavior === 'retry' && config?.backoffEnabled === false) { + return new ErrorClassification('permanent'); + } return new ErrorClassification( behavior === 'retry' ? 'transient' : 'permanent' ); diff --git a/packages/core/src/plugins/SegmentDestination.ts b/packages/core/src/plugins/SegmentDestination.ts index b802c0d04..fb0a7e825 100644 --- a/packages/core/src/plugins/SegmentDestination.ts +++ b/packages/core/src/plugins/SegmentDestination.ts @@ -25,6 +25,7 @@ import { } from '../errors'; import { RetryManager } from '../backoff/RetryManager'; import type { RetryResult } from '../backoff'; +import { extractHttpConfig } from '../config-validation'; const MAX_EVENTS_PER_BATCH = 100; const MAX_PAYLOAD_SIZE_IN_KB = 500; @@ -86,6 +87,7 @@ export class SegmentDestination extends DestinationPlugin { default5xxBehavior: this.getBackoffConfig()?.default5xxBehavior, statusCodeOverrides: this.getBackoffConfig()?.statusCodeOverrides, rateLimitEnabled: this.getRateLimitConfig()?.enabled, + backoffEnabled: this.getBackoffConfig()?.enabled, }); switch (classification.errorType) { @@ -419,7 +421,22 @@ export class SegmentDestination extends DestinationPlugin { this.apiHost = `https://${segmentSettings.apiHost}/b`; } - const httpConfig = this.analytics?.getHttpConfig(); + // Read httpConfig: prefer integration-level settings from CDN, fall back to + // top-level CDN config merged with client config (via analytics.getHttpConfig()). + const rawIntegration = settings.integrations[this.key] as + | Record + | undefined; + let httpConfig: HttpConfig | undefined; + if (rawIntegration?.httpConfig) { + httpConfig = extractHttpConfig( + rawIntegration.httpConfig as HttpConfig, + this.analytics?.logger + ); + } + if (!httpConfig) { + httpConfig = this.analytics?.getHttpConfig(); + } + if (httpConfig) { this.httpConfig = httpConfig; From 51d9a8cda657f0b7a2acfad541964c106e55a28a Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Thu, 26 Mar 2026 18:34:51 -0400 Subject: [PATCH 2/2] fix: use explicit comparison to satisfy strict-boolean-expressions lint Co-Authored-By: Claude Opus 4.6 --- packages/core/src/plugins/SegmentDestination.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/plugins/SegmentDestination.ts b/packages/core/src/plugins/SegmentDestination.ts index fb0a7e825..b291c8b9d 100644 --- a/packages/core/src/plugins/SegmentDestination.ts +++ b/packages/core/src/plugins/SegmentDestination.ts @@ -427,7 +427,7 @@ export class SegmentDestination extends DestinationPlugin { | Record | undefined; let httpConfig: HttpConfig | undefined; - if (rawIntegration?.httpConfig) { + if (rawIntegration?.httpConfig !== undefined) { httpConfig = extractHttpConfig( rawIntegration.httpConfig as HttpConfig, this.analytics?.logger