From 53b06dc780cdc1bf5ee6caa735a3045bb8b8577f Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 12:09:54 +0200 Subject: [PATCH 1/9] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20expose=20the=20build-t?= =?UTF-8?q?ime=20SDK=20setup=20as=20a=20mockable=20accessor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../browser-core/src/domain/telemetry/telemetry.ts | 5 +++-- packages/browser-core/src/index.ts | 1 + packages/browser-core/src/tools/getSdkSetup.spec.ts | 9 +++++++++ packages/browser-core/src/tools/getSdkSetup.ts | 12 ++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 packages/browser-core/src/tools/getSdkSetup.spec.ts create mode 100644 packages/browser-core/src/tools/getSdkSetup.ts diff --git a/packages/browser-core/src/domain/telemetry/telemetry.ts b/packages/browser-core/src/domain/telemetry/telemetry.ts index d4a6f9d876..cb7bea286e 100644 --- a/packages/browser-core/src/domain/telemetry/telemetry.ts +++ b/packages/browser-core/src/domain/telemetry/telemetry.ts @@ -28,6 +28,8 @@ import { computeStackTrace } from '../../tools/stackTrace/computeStackTrace' import { getConnectivity } from '../connectivity' import { canUseEventBridge, getEventBridge, createBatch } from '../../transport' import { noop } from '../../tools/utils/functionUtils' +import { mockable } from '../../tools/mockable' +import { getSdkSetup } from '../../tools/getSdkSetup' import type { TelemetryEvent } from './telemetryEvent.types' import type { RawTelemetryConfiguration, @@ -39,7 +41,6 @@ import { StatusType, TelemetryType } from './rawTelemetryEvent.types' // replaced at build time declare const __BUILD_ENV__SDK_VERSION__: string -declare const __BUILD_ENV__SDK_SETUP__: string const ALLOWED_FRAME_URLS = [ 'https://www.datadoghq-browser-agent.com', @@ -195,7 +196,7 @@ export function startTelemetryCollection( telemetry: combine(rawEvent, { runtime_env: runtimeEnvInfo, connectivity: getConnectivity(), - sdk_setup: __BUILD_ENV__SDK_SETUP__, + sdk_setup: mockable(getSdkSetup)(), sdk_name: sdkName, }) as TelemetryEvent['telemetry'], ddtags: buildTags(configuration).join(','), diff --git a/packages/browser-core/src/index.ts b/packages/browser-core/src/index.ts index c6adc82e66..60d5e3c638 100644 --- a/packages/browser-core/src/index.ts +++ b/packages/browser-core/src/index.ts @@ -88,6 +88,7 @@ export { sendToExtension } from './tools/sendToExtension' export { runOnReadyState, asyncRunOnReadyState } from './browser/runOnReadyState' export { getZoneJsOriginalValue } from './tools/getZoneJsOriginalValue' export { mockable } from './tools/mockable' +export { getSdkSetup } from './tools/getSdkSetup' export type { InstrumentedMethodCall, InstrumentedConstructorCall } from './tools/instrumentMethod' export { instrumentMethod, instrumentConstructor, instrumentSetter } from './tools/instrumentMethod' export { diff --git a/packages/browser-core/src/tools/getSdkSetup.spec.ts b/packages/browser-core/src/tools/getSdkSetup.spec.ts new file mode 100644 index 0000000000..4ed93df2cb --- /dev/null +++ b/packages/browser-core/src/tools/getSdkSetup.spec.ts @@ -0,0 +1,9 @@ +import { getSdkSetup } from './getSdkSetup' + +describe('getSdkSetup', () => { + it('returns the setup the bundle was built for', () => { + // Unit tests are bundled by webpack.base.ts, which defines the setup as 'cdn'. Tests that + // need to exercise the npm code path mock this function with `replaceMockable`. + expect(getSdkSetup()).toBe('cdn') + }) +}) diff --git a/packages/browser-core/src/tools/getSdkSetup.ts b/packages/browser-core/src/tools/getSdkSetup.ts new file mode 100644 index 0000000000..8c9422622a --- /dev/null +++ b/packages/browser-core/src/tools/getSdkSetup.ts @@ -0,0 +1,12 @@ +// replaced at build time +declare const __BUILD_ENV__SDK_SETUP__: 'npm' | 'cdn' + +/** + * The distribution channel this bundle was built for: `'cdn'` for the CDN bundles (webpack) and + * `'npm'` for the published packages (esbuild). See `scripts/lib/buildEnv.ts`. + * + * Call sites should wrap this with `mockable()` so tests can exercise the other channel. + */ +export function getSdkSetup() { + return __BUILD_ENV__SDK_SETUP__ +} From 5eb08c101697a8e212696e0540d1d05378345140 Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 12:12:54 +0200 Subject: [PATCH 2/9] =?UTF-8?q?=E2=9C=A8=20enable=20partial=20view=20updat?= =?UTF-8?q?es=20by=20default=20for=20CDN=20users=20without=20a=20proxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/configuration.spec.ts | 100 +++++++++++++++++- .../src/domain/configuration/configuration.ts | 28 ++++- 2 files changed, 124 insertions(+), 4 deletions(-) diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts b/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts index 3eb13b6235..f8919b57e1 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts @@ -4,6 +4,7 @@ import { DefaultPrivacyLevel, display, ExperimentalFeature, + getSdkSetup, TraceContextInjection, } from '@datadog/browser-core' import type { @@ -11,7 +12,11 @@ import type { CamelToSnakeCase, MapInitConfigurationKey, } from '@datadog/browser-core/test' -import { EXHAUSTIVE_INIT_CONFIGURATION, SERIALIZED_EXHAUSTIVE_INIT_CONFIGURATION } from '@datadog/browser-core/test' +import { + EXHAUSTIVE_INIT_CONFIGURATION, + replaceMockable, + SERIALIZED_EXHAUSTIVE_INIT_CONFIGURATION, +} from '@datadog/browser-core/test' import type { RumInitConfiguration } from './configuration' import { DEFAULT_PROPAGATOR_TYPES, @@ -486,6 +491,74 @@ describe('validateAndBuildRumConfiguration', () => { }) }) + describe('betaEnableViewUpdates', () => { + // Unit tests are bundled as a CDN build (see webpack.base.ts), so the npm cases mock + // `getSdkSetup`. `getSdkSetup.spec.ts` pins that 'cdn' assumption. + + it('defaults to true on a CDN build without a proxy', () => { + expect(validateAndBuildRumConfiguration(DEFAULT_INIT_CONFIGURATION)!.betaEnableViewUpdates).toBeTrue() + }) + + it('defaults to false on a CDN build with a proxy', () => { + expect( + validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, proxy: 'https://proxy.example.com' })! + .betaEnableViewUpdates + ).toBeFalse() + }) + + it('defaults to false on a CDN build with a proxy function', () => { + expect( + validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, proxy: () => 'https://proxy.example.com' })! + .betaEnableViewUpdates + ).toBeFalse() + }) + + it('defaults to false on an npm build without a proxy', () => { + replaceMockable(getSdkSetup, () => 'npm' as const) + expect(validateAndBuildRumConfiguration(DEFAULT_INIT_CONFIGURATION)!.betaEnableViewUpdates).toBeFalse() + }) + + it('defaults to false on an npm build with a proxy', () => { + replaceMockable(getSdkSetup, () => 'npm' as const) + expect( + validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, proxy: 'https://proxy.example.com' })! + .betaEnableViewUpdates + ).toBeFalse() + }) + + it('honors an explicit false on a CDN build without a proxy', () => { + expect( + validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: false })! + .betaEnableViewUpdates + ).toBeFalse() + }) + + it('honors an explicit true on a CDN build with a proxy', () => { + expect( + validateAndBuildRumConfiguration({ + ...DEFAULT_INIT_CONFIGURATION, + betaEnableViewUpdates: true, + proxy: 'https://proxy.example.com', + })!.betaEnableViewUpdates + ).toBeTrue() + }) + + it('honors an explicit true on an npm build', () => { + replaceMockable(getSdkSetup, () => 'npm' as const) + expect( + validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: true })! + .betaEnableViewUpdates + ).toBeTrue() + }) + + it('does not validate the configuration if it is not a boolean', () => { + expect( + validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: 'yes' as any }) + ).toBeUndefined() + expect(displayErrorSpy).toHaveBeenCalledOnceWith('"betaEnableViewUpdates" must be a boolean') + }) + }) + describe('trackResourceHeaders', () => { describe('disabled', () => { it('defaults to empty array', () => { @@ -919,6 +992,31 @@ describe('validateAndBuildRumConfiguration', () => { }) describe('serializeRumConfiguration', () => { + describe('beta_enable_view_updates', () => { + it('reports the effective default on a CDN build without a proxy', () => { + expect(serializeRumConfiguration(DEFAULT_INIT_CONFIGURATION).beta_enable_view_updates).toBeTrue() + }) + + it('reports the effective default on a CDN build with a proxy', () => { + expect( + serializeRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, proxy: 'https://proxy.example.com' }) + .beta_enable_view_updates + ).toBeFalse() + }) + + it('reports the effective default on an npm build', () => { + replaceMockable(getSdkSetup, () => 'npm' as const) + expect(serializeRumConfiguration(DEFAULT_INIT_CONFIGURATION).beta_enable_view_updates).toBeFalse() + }) + + it('reports an explicitly disabled option', () => { + expect( + serializeRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: false }) + .beta_enable_view_updates + ).toBeFalse() + }) + }) + it('should serialize the configuration', () => { const exhaustiveRumInitConfiguration: Required = { ...EXHAUSTIVE_INIT_CONFIGURATION, diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.ts b/packages/browser-rum-core/src/domain/configuration/configuration.ts index 49999e317e..c61544cee8 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.ts @@ -6,9 +6,11 @@ import { TraceContextInjection, display, ExperimentalFeature, + getSdkSetup, isExperimentalFeatureEnabled, isNumber, isNonEmptyArray, + mockable, BROWSER_CORE_SCHEMA, } from '@datadog/browser-core' import { isIndexableObject, isMatchOption } from '@datadog/js-core/util' @@ -350,6 +352,9 @@ export interface RumInitConfiguration extends InitConfiguration { * Enable partial view updates, which reduces bandwidth by sending only changed * fields instead of full view events on intermediate updates. * + * Enabled by default when the SDK is loaded from the CDN and no `proxy` is configured. + * Disabled by default otherwise, because a proxy may not forward the `view_update` event type. + * * @category Beta */ betaEnableViewUpdates?: boolean | undefined @@ -413,7 +418,9 @@ export const RUM_SCHEMA = { trackResources: { type: 'boolean', default: true, strict: false }, trackLongTasks: { type: 'boolean', default: true, strict: false }, trackViewsManually: { type: 'boolean', default: false, strict: false }, - betaEnableViewUpdates: { type: 'boolean', default: false }, + // No `default`: an unset option must stay distinguishable from an explicit `false` so + // `validateAndBuildRumConfiguration` can apply the conditional default below. + betaEnableViewUpdates: { type: 'boolean' }, betaTrackWebSockets: { type: 'boolean', default: false, strict: false }, enablePrivacyForActionName: { type: 'boolean', default: true }, propagateTraceBaggage: { type: 'boolean', default: true }, @@ -489,14 +496,27 @@ export const RUM_SCHEMA = { }, } as const -export type RumConfiguration = Omit, 'allowedTracingUrls'> & { +export type RumConfiguration = Omit< + InferredConfig, + 'allowedTracingUrls' | 'betaEnableViewUpdates' +> & { allowedTracingUrls: TracingOption[] + betaEnableViewUpdates: boolean rulePsr: number | undefined trackResourceHeaders: MatchHeader[] allowedGraphQlUrls: GraphQlUrlOption[] remoteConfigurationId: string | undefined } +/** + * Partial view updates are enabled by default for CDN users that do not go through a proxy: a + * proxy may not forward the `view_update` event type yet, and npm users pin an SDK version so + * they opt in explicitly. An explicit `betaEnableViewUpdates` always takes precedence. + */ +function isViewUpdatesEnabledByDefault(proxy: InitConfiguration['proxy']): boolean { + return mockable(getSdkSetup)() === 'cdn' && !proxy +} + export function validateAndBuildRumConfiguration( initConfiguration: RumInitConfiguration ): RumConfiguration | undefined { @@ -524,6 +544,7 @@ export function validateAndBuildRumConfiguration( return { ...config, sessionReplayCanvasRecording, + betaEnableViewUpdates: config.betaEnableViewUpdates ?? isViewUpdatesEnabledByDefault(config.proxy), allowedTracingUrls, beforeSend: config.beforeSend ? (catchUserErrors(config.beforeSend, 'beforeSend threw an error:') as typeof config.beforeSend) @@ -718,7 +739,8 @@ export function serializeRumConfiguration(configuration: RumInitConfiguration) { profiling_sample_rate: configuration.profilingSampleRate, use_remote_configuration_proxy: !!configuration.remoteConfigurationProxy, track_resource_headers: getTrackResourceHeadersTelemetryValue(configuration.trackResourceHeaders), - beta_enable_view_updates: configuration.betaEnableViewUpdates, + beta_enable_view_updates: + configuration.betaEnableViewUpdates ?? isViewUpdatesEnabledByDefault(configuration.proxy), beta_track_web_sockets: configuration.betaTrackWebSockets, ...baseSerializedConfiguration, } satisfies RawTelemetryConfiguration From b470521f43eed91bbd31ed0c5ddc9c0d2a59ff30 Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 12:52:51 +0200 Subject: [PATCH 3/9] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20read=20the=20build-env?= =?UTF-8?q?=20setup=20locally=20instead=20of=20via=20a=20shared=20accessor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts the getSdkSetup accessor and its browser-core export. rum-core now declares __BUILD_ENV__SDK_SETUP__ locally, like the eight existing __BUILD_ENV__SDK_VERSION__ consumers. Drops the four npm-branch tests, which are unreachable under Karma because webpack.base.ts pins setup: 'cdn'. Also fixes prettier on the beta_enable_view_updates line. --- .../src/domain/telemetry/telemetry.ts | 5 +-- packages/browser-core/src/index.ts | 1 - .../src/tools/getSdkSetup.spec.ts | 9 ----- .../browser-core/src/tools/getSdkSetup.ts | 12 ------ .../configuration/configuration.spec.ts | 37 ++----------------- .../src/domain/configuration/configuration.ts | 10 ++--- 6 files changed, 10 insertions(+), 64 deletions(-) delete mode 100644 packages/browser-core/src/tools/getSdkSetup.spec.ts delete mode 100644 packages/browser-core/src/tools/getSdkSetup.ts diff --git a/packages/browser-core/src/domain/telemetry/telemetry.ts b/packages/browser-core/src/domain/telemetry/telemetry.ts index cb7bea286e..d4a6f9d876 100644 --- a/packages/browser-core/src/domain/telemetry/telemetry.ts +++ b/packages/browser-core/src/domain/telemetry/telemetry.ts @@ -28,8 +28,6 @@ import { computeStackTrace } from '../../tools/stackTrace/computeStackTrace' import { getConnectivity } from '../connectivity' import { canUseEventBridge, getEventBridge, createBatch } from '../../transport' import { noop } from '../../tools/utils/functionUtils' -import { mockable } from '../../tools/mockable' -import { getSdkSetup } from '../../tools/getSdkSetup' import type { TelemetryEvent } from './telemetryEvent.types' import type { RawTelemetryConfiguration, @@ -41,6 +39,7 @@ import { StatusType, TelemetryType } from './rawTelemetryEvent.types' // replaced at build time declare const __BUILD_ENV__SDK_VERSION__: string +declare const __BUILD_ENV__SDK_SETUP__: string const ALLOWED_FRAME_URLS = [ 'https://www.datadoghq-browser-agent.com', @@ -196,7 +195,7 @@ export function startTelemetryCollection( telemetry: combine(rawEvent, { runtime_env: runtimeEnvInfo, connectivity: getConnectivity(), - sdk_setup: mockable(getSdkSetup)(), + sdk_setup: __BUILD_ENV__SDK_SETUP__, sdk_name: sdkName, }) as TelemetryEvent['telemetry'], ddtags: buildTags(configuration).join(','), diff --git a/packages/browser-core/src/index.ts b/packages/browser-core/src/index.ts index 60d5e3c638..c6adc82e66 100644 --- a/packages/browser-core/src/index.ts +++ b/packages/browser-core/src/index.ts @@ -88,7 +88,6 @@ export { sendToExtension } from './tools/sendToExtension' export { runOnReadyState, asyncRunOnReadyState } from './browser/runOnReadyState' export { getZoneJsOriginalValue } from './tools/getZoneJsOriginalValue' export { mockable } from './tools/mockable' -export { getSdkSetup } from './tools/getSdkSetup' export type { InstrumentedMethodCall, InstrumentedConstructorCall } from './tools/instrumentMethod' export { instrumentMethod, instrumentConstructor, instrumentSetter } from './tools/instrumentMethod' export { diff --git a/packages/browser-core/src/tools/getSdkSetup.spec.ts b/packages/browser-core/src/tools/getSdkSetup.spec.ts deleted file mode 100644 index 4ed93df2cb..0000000000 --- a/packages/browser-core/src/tools/getSdkSetup.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getSdkSetup } from './getSdkSetup' - -describe('getSdkSetup', () => { - it('returns the setup the bundle was built for', () => { - // Unit tests are bundled by webpack.base.ts, which defines the setup as 'cdn'. Tests that - // need to exercise the npm code path mock this function with `replaceMockable`. - expect(getSdkSetup()).toBe('cdn') - }) -}) diff --git a/packages/browser-core/src/tools/getSdkSetup.ts b/packages/browser-core/src/tools/getSdkSetup.ts deleted file mode 100644 index 8c9422622a..0000000000 --- a/packages/browser-core/src/tools/getSdkSetup.ts +++ /dev/null @@ -1,12 +0,0 @@ -// replaced at build time -declare const __BUILD_ENV__SDK_SETUP__: 'npm' | 'cdn' - -/** - * The distribution channel this bundle was built for: `'cdn'` for the CDN bundles (webpack) and - * `'npm'` for the published packages (esbuild). See `scripts/lib/buildEnv.ts`. - * - * Call sites should wrap this with `mockable()` so tests can exercise the other channel. - */ -export function getSdkSetup() { - return __BUILD_ENV__SDK_SETUP__ -} diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts b/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts index f8919b57e1..8f6ec47ffa 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.spec.ts @@ -4,7 +4,6 @@ import { DefaultPrivacyLevel, display, ExperimentalFeature, - getSdkSetup, TraceContextInjection, } from '@datadog/browser-core' import type { @@ -12,11 +11,7 @@ import type { CamelToSnakeCase, MapInitConfigurationKey, } from '@datadog/browser-core/test' -import { - EXHAUSTIVE_INIT_CONFIGURATION, - replaceMockable, - SERIALIZED_EXHAUSTIVE_INIT_CONFIGURATION, -} from '@datadog/browser-core/test' +import { EXHAUSTIVE_INIT_CONFIGURATION, SERIALIZED_EXHAUSTIVE_INIT_CONFIGURATION } from '@datadog/browser-core/test' import type { RumInitConfiguration } from './configuration' import { DEFAULT_PROPAGATOR_TYPES, @@ -492,8 +487,8 @@ describe('validateAndBuildRumConfiguration', () => { }) describe('betaEnableViewUpdates', () => { - // Unit tests are bundled as a CDN build (see webpack.base.ts), so the npm cases mock - // `getSdkSetup`. `getSdkSetup.spec.ts` pins that 'cdn' assumption. + // Unit tests are bundled as a CDN build (webpack.base.ts pins `setup: 'cdn'`), so the npm + // side of the default is only covered by e2e and by reading the code. it('defaults to true on a CDN build without a proxy', () => { expect(validateAndBuildRumConfiguration(DEFAULT_INIT_CONFIGURATION)!.betaEnableViewUpdates).toBeTrue() @@ -513,19 +508,6 @@ describe('validateAndBuildRumConfiguration', () => { ).toBeFalse() }) - it('defaults to false on an npm build without a proxy', () => { - replaceMockable(getSdkSetup, () => 'npm' as const) - expect(validateAndBuildRumConfiguration(DEFAULT_INIT_CONFIGURATION)!.betaEnableViewUpdates).toBeFalse() - }) - - it('defaults to false on an npm build with a proxy', () => { - replaceMockable(getSdkSetup, () => 'npm' as const) - expect( - validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, proxy: 'https://proxy.example.com' })! - .betaEnableViewUpdates - ).toBeFalse() - }) - it('honors an explicit false on a CDN build without a proxy', () => { expect( validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: false })! @@ -543,14 +525,6 @@ describe('validateAndBuildRumConfiguration', () => { ).toBeTrue() }) - it('honors an explicit true on an npm build', () => { - replaceMockable(getSdkSetup, () => 'npm' as const) - expect( - validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: true })! - .betaEnableViewUpdates - ).toBeTrue() - }) - it('does not validate the configuration if it is not a boolean', () => { expect( validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: 'yes' as any }) @@ -1004,11 +978,6 @@ describe('serializeRumConfiguration', () => { ).toBeFalse() }) - it('reports the effective default on an npm build', () => { - replaceMockable(getSdkSetup, () => 'npm' as const) - expect(serializeRumConfiguration(DEFAULT_INIT_CONFIGURATION).beta_enable_view_updates).toBeFalse() - }) - it('reports an explicitly disabled option', () => { expect( serializeRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, betaEnableViewUpdates: false }) diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.ts b/packages/browser-rum-core/src/domain/configuration/configuration.ts index c61544cee8..832d532879 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.ts @@ -6,11 +6,9 @@ import { TraceContextInjection, display, ExperimentalFeature, - getSdkSetup, isExperimentalFeatureEnabled, isNumber, isNonEmptyArray, - mockable, BROWSER_CORE_SCHEMA, } from '@datadog/browser-core' import { isIndexableObject, isMatchOption } from '@datadog/js-core/util' @@ -22,6 +20,9 @@ import type { RumPlugin } from '../plugins' import type { PropagatorType, TracingOption } from '../tracing/tracer.types' import { getRemoteConfigurationId } from './remoteConfiguration' +// replaced at build time +declare const __BUILD_ENV__SDK_SETUP__: 'npm' | 'cdn' + export const DEFAULT_PROPAGATOR_TYPES: PropagatorType[] = ['tracecontext', 'datadog'] /** @@ -514,7 +515,7 @@ export type RumConfiguration = Omit< * they opt in explicitly. An explicit `betaEnableViewUpdates` always takes precedence. */ function isViewUpdatesEnabledByDefault(proxy: InitConfiguration['proxy']): boolean { - return mockable(getSdkSetup)() === 'cdn' && !proxy + return __BUILD_ENV__SDK_SETUP__ === 'cdn' && !proxy } export function validateAndBuildRumConfiguration( @@ -739,8 +740,7 @@ export function serializeRumConfiguration(configuration: RumInitConfiguration) { profiling_sample_rate: configuration.profilingSampleRate, use_remote_configuration_proxy: !!configuration.remoteConfigurationProxy, track_resource_headers: getTrackResourceHeadersTelemetryValue(configuration.trackResourceHeaders), - beta_enable_view_updates: - configuration.betaEnableViewUpdates ?? isViewUpdatesEnabledByDefault(configuration.proxy), + beta_enable_view_updates: configuration.betaEnableViewUpdates ?? isViewUpdatesEnabledByDefault(configuration.proxy), beta_track_web_sockets: configuration.betaTrackWebSockets, ...baseSerializedConfiguration, } satisfies RawTelemetryConfiguration From 0ab58cf44df1f8fe13aaa428d984ecc953e36888 Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 17:11:11 +0200 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=8E=A8=20type=20the=20build-env=20set?= =?UTF-8?q?up=20declare=20as=20the=20union=20it=20actually=20is?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both declares of __BUILD_ENV__SDK_SETUP__ now read 'npm' | 'cdn', matching the setup argument of getBuildEnvDefines. With the previous 'string' type a typo like === 'CDN' would compile and silently disable the feature. --- packages/browser-core/src/domain/telemetry/telemetry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-core/src/domain/telemetry/telemetry.ts b/packages/browser-core/src/domain/telemetry/telemetry.ts index d4a6f9d876..5e80aac18e 100644 --- a/packages/browser-core/src/domain/telemetry/telemetry.ts +++ b/packages/browser-core/src/domain/telemetry/telemetry.ts @@ -39,7 +39,7 @@ import { StatusType, TelemetryType } from './rawTelemetryEvent.types' // replaced at build time declare const __BUILD_ENV__SDK_VERSION__: string -declare const __BUILD_ENV__SDK_SETUP__: string +declare const __BUILD_ENV__SDK_SETUP__: 'npm' | 'cdn' const ALLOWED_FRAME_URLS = [ 'https://www.datadoghq-browser-agent.com', From 6baf5d4d7d4e5cdc8475375a424b01269344268e Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 17:23:18 +0200 Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=A7=B9=20drop=20the=20schema=20commen?= =?UTF-8?q?t,=20the=20rationale=20lives=20in=20the=20PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../browser-rum-core/src/domain/configuration/configuration.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.ts b/packages/browser-rum-core/src/domain/configuration/configuration.ts index 832d532879..508c7aa536 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.ts @@ -419,8 +419,6 @@ export const RUM_SCHEMA = { trackResources: { type: 'boolean', default: true, strict: false }, trackLongTasks: { type: 'boolean', default: true, strict: false }, trackViewsManually: { type: 'boolean', default: false, strict: false }, - // No `default`: an unset option must stay distinguishable from an explicit `false` so - // `validateAndBuildRumConfiguration` can apply the conditional default below. betaEnableViewUpdates: { type: 'boolean' }, betaTrackWebSockets: { type: 'boolean', default: false, strict: false }, enablePrivacyForActionName: { type: 'boolean', default: true }, From 97d56478097c11150543f70e289ad73760d2c672 Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 17:50:53 +0200 Subject: [PATCH 6/9] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20drop=20the=20redundant?= =?UTF-8?q?=20Omit=20entry=20for=20betaEnableViewUpdates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The intersection already resolves it: (boolean | undefined) & boolean is boolean, and the required member wins over the optional one. Only allowedTracingUrls needs the Omit, because its schema type and resolved type are incompatible. --- .../src/domain/configuration/configuration.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.ts b/packages/browser-rum-core/src/domain/configuration/configuration.ts index 508c7aa536..8aeca3fb84 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.ts @@ -495,10 +495,7 @@ export const RUM_SCHEMA = { }, } as const -export type RumConfiguration = Omit< - InferredConfig, - 'allowedTracingUrls' | 'betaEnableViewUpdates' -> & { +export type RumConfiguration = Omit, 'allowedTracingUrls'> & { allowedTracingUrls: TracingOption[] betaEnableViewUpdates: boolean rulePsr: number | undefined From 02a03c4077a7465bf119e90c75a0d74650a300aa Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 18:00:01 +0200 Subject: [PATCH 7/9] =?UTF-8?q?=F0=9F=93=9D=20note=20that=20the=20CDN=20ch?= =?UTF-8?q?eck=20is=20temporary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../browser-rum-core/src/domain/configuration/configuration.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.ts b/packages/browser-rum-core/src/domain/configuration/configuration.ts index 8aeca3fb84..580c130d8d 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.ts @@ -508,6 +508,9 @@ export type RumConfiguration = Omit, 'allowedT * Partial view updates are enabled by default for CDN users that do not go through a proxy: a * proxy may not forward the `view_update` event type yet, and npm users pin an SDK version so * they opt in explicitly. An explicit `betaEnableViewUpdates` always takes precedence. + * + * The CDN check is temporary, the next step is to default this to true unless `proxy` is set. + * TODO next major: remove the option. */ function isViewUpdatesEnabledByDefault(proxy: InitConfiguration['proxy']): boolean { return __BUILD_ENV__SDK_SETUP__ === 'cdn' && !proxy From 942876bab2eceb78a8d8227bb7514c21d70f504c Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 18:10:15 +0200 Subject: [PATCH 8/9] =?UTF-8?q?=E2=8F=AA=EF=B8=8F=20keep=20the=20telemetry?= =?UTF-8?q?=20declare=20as=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sdk_setup is merged in via combine() and cast to TelemetryEvent['telemetry'], so the type is never checked there. The narrow only pays off in rum-core where the value is compared against 'cdn'. Leaving telemetry.ts untouched avoids a declare that can go stale if a third setup is ever added. --- packages/browser-core/src/domain/telemetry/telemetry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-core/src/domain/telemetry/telemetry.ts b/packages/browser-core/src/domain/telemetry/telemetry.ts index 5e80aac18e..d4a6f9d876 100644 --- a/packages/browser-core/src/domain/telemetry/telemetry.ts +++ b/packages/browser-core/src/domain/telemetry/telemetry.ts @@ -39,7 +39,7 @@ import { StatusType, TelemetryType } from './rawTelemetryEvent.types' // replaced at build time declare const __BUILD_ENV__SDK_VERSION__: string -declare const __BUILD_ENV__SDK_SETUP__: 'npm' | 'cdn' +declare const __BUILD_ENV__SDK_SETUP__: string const ALLOWED_FRAME_URLS = [ 'https://www.datadoghq-browser-agent.com', From f99fe237d734f2d9da5d09821085f686ce2f2b40 Mon Sep 17 00:00:00 2001 From: Adrian de la Rosa Date: Mon, 31 Aug 2026 18:17:12 +0200 Subject: [PATCH 9/9] =?UTF-8?q?=E2=8F=AA=EF=B8=8F=20declare=20the=20build-?= =?UTF-8?q?env=20setup=20as=20string,=20like=20every=20other=20build-env?= =?UTF-8?q?=20global?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The narrow only guarded a typo in === 'cdn', which the tests already catch. string matches the telemetry declare and the eight __BUILD_ENV__SDK_VERSION__ ones. --- .../browser-rum-core/src/domain/configuration/configuration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-rum-core/src/domain/configuration/configuration.ts b/packages/browser-rum-core/src/domain/configuration/configuration.ts index 580c130d8d..7f88a0de68 100644 --- a/packages/browser-rum-core/src/domain/configuration/configuration.ts +++ b/packages/browser-rum-core/src/domain/configuration/configuration.ts @@ -21,7 +21,7 @@ import type { PropagatorType, TracingOption } from '../tracing/tracer.types' import { getRemoteConfigurationId } from './remoteConfiguration' // replaced at build time -declare const __BUILD_ENV__SDK_SETUP__: 'npm' | 'cdn' +declare const __BUILD_ENV__SDK_SETUP__: string export const DEFAULT_PROPAGATOR_TYPES: PropagatorType[] = ['tracecontext', 'datadog']