Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { EndpointBuilder, InitConfiguration } from '@datadog/browser-core'
import { computeTransportConfiguration } from '../../../../../../packages/core/src/domain/configuration'
import { createEndpointBuilder } from '@datadog/browser-core'
import { copy } from '../../../copy'
import type { SdkInfos } from '../../../hooks/useSdkInfos'
import type { SdkEvent } from '../../../sdkEvent'
Expand Down Expand Up @@ -75,7 +75,7 @@ export function getIntakeUrlForEvent(sdkInfos: SdkInfos, event: SdkEvent) {
return
}
version = sdkInfos.rum.version
builder = computeTransportConfiguration(sdkInfos.rum.config as InitConfiguration).rumEndpointBuilder
builder = createEndpointBuilder(sdkInfos.rum.config as InitConfiguration, 'rum')
break
}

Expand All @@ -84,7 +84,7 @@ export function getIntakeUrlForEvent(sdkInfos: SdkInfos, event: SdkEvent) {
return
}
version = sdkInfos.logs.version
builder = computeTransportConfiguration(sdkInfos.logs.config as InitConfiguration).logsEndpointBuilder
builder = createEndpointBuilder(sdkInfos.logs.config as InitConfiguration, 'logs')
break
}

Expand Down
35 changes: 35 additions & 0 deletions packages/core/src/domain/configuration/configuration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
isExperimentalFeatureEnabled,
resetExperimentalFeatures,
} from '../../tools/experimentalFeatures'
import { INTAKE_SITE_FED_STAGING } from '../intakeSites'
import { SessionPersistence } from '../session/sessionConstants'
import { TrackingConsent } from '../trackingConsent'
import type { InitConfiguration } from './configuration'
Expand Down Expand Up @@ -189,6 +190,40 @@ describe('validateAndBuildConfiguration', () => {
})
})

describe('site', () => {
it('should use US site by default', () => {
const configuration = validateAndBuildConfiguration({ clientToken })
expect(configuration!.site).toBe('datadoghq.com')
})

it('should use logs intake domain for fed staging', () => {
const configuration = validateAndBuildConfiguration({ clientToken, site: INTAKE_SITE_FED_STAGING })
expect(configuration!.site).toBe(INTAKE_SITE_FED_STAGING)
})

it('should use site value when set', () => {
const configuration = validateAndBuildConfiguration({ clientToken, site: 'datadoghq.com' })
expect(configuration!.site).toBe('datadoghq.com')
})
})

describe('internalAnalyticsSubdomain', () => {
it('defaults to undefined', () => {
const configuration = validateAndBuildConfiguration({
clientToken,
})
expect(configuration!.internalAnalyticsSubdomain).toBeUndefined()
})

it('is set to the provided value', () => {
const configuration = validateAndBuildConfiguration({
clientToken,
internalAnalyticsSubdomain: 'ia-rum-intake',
})
expect(configuration!.internalAnalyticsSubdomain).toBe('ia-rum-intake')
})
})

describe('env parameter validation', () => {
it('should validate the env parameter', () => {
validateAndBuildConfiguration({ clientToken, env: false as any })
Expand Down
30 changes: 25 additions & 5 deletions packages/core/src/domain/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import { TrackingConsent } from '../trackingConsent'
import type { SessionPersistence } from '../session/sessionConstants'
import type { MatchOption } from '../../tools/matchOption'
import { isAllowedTrackingOrigins } from '../allowedTrackingOrigins'
import { INTAKE_SITE_US1 } from '../intakeSites'
import type { Site } from '../intakeSites'
import { isWorkerEnvironment } from '../../tools/globalObject'
import type { TransportConfiguration } from './transportConfiguration'
import { computeTransportConfiguration } from './transportConfiguration'

/**
* Default privacy level for the browser SDK.
Expand Down Expand Up @@ -308,8 +307,10 @@ export interface ReplicaUserConfiguration {
clientToken: string
}

export interface Configuration extends TransportConfiguration {
export interface Configuration {
// Built from init configuration
clientToken: string
site: Site
beforeSend: GenericBeforeSendCallback | undefined
sessionStoreStrategyType: SessionStoreStrategyType | undefined
sessionSampleRate: number
Expand All @@ -325,11 +326,18 @@ export interface Configuration extends TransportConfiguration {
storeContextsAcrossPages: boolean
trackAnonymousUser?: boolean
betaEncodeCookieOptions: boolean
datacenter: string | undefined
proxy: ProxyFn | string | undefined

// TODO(next-major): remove this
usePciIntake: boolean

// internal
sdkVersion: string | undefined
source: 'browser' | 'flutter' | 'unity'
variant: string | undefined
replica: ReplicaUserConfiguration | undefined
internalAnalyticsSubdomain: string | undefined
}

function isString(tag: unknown, tagName: string): tag is string | undefined | null {
Expand Down Expand Up @@ -396,6 +404,7 @@ export function validateAndBuildConfiguration(
}

return {
site: initConfiguration.site || INTAKE_SITE_US1,
beforeSend:
initConfiguration.beforeSend && catchUserErrors(initConfiguration.beforeSend, 'beforeSend threw an error:'),
sessionStoreStrategyType: isWorkerEnvironment ? undefined : selectSessionStoreStrategyType(initConfiguration),
Expand All @@ -413,14 +422,18 @@ export function validateAndBuildConfiguration(
trackAnonymousUser: initConfiguration.trackAnonymousUser ?? true,
storeContextsAcrossPages: !!initConfiguration.storeContextsAcrossPages,
betaEncodeCookieOptions: !!initConfiguration.betaEncodeCookieOptions,
replica: initConfiguration.replica,
proxy: initConfiguration.proxy,
internalAnalyticsSubdomain: initConfiguration.internalAnalyticsSubdomain,
clientToken: initConfiguration.clientToken,
usePciIntake: false,

/**
* The source of the SDK, used for support plugins purposes.
*/
variant: initConfiguration.variant,
sdkVersion: initConfiguration.sdkVersion,

...computeTransportConfiguration(initConfiguration),
source: validateSource(initConfiguration.source),
}
}

Expand Down Expand Up @@ -449,3 +462,10 @@ export function serializeConfiguration(initConfiguration: InitConfiguration) {
variant: initConfiguration.variant,
} satisfies RawTelemetryConfiguration
}

function validateSource(source: string | undefined) {
if (source === 'flutter' || source === 'unity') {
return source
}
return 'browser'
}
86 changes: 53 additions & 33 deletions packages/core/src/domain/configuration/endpointBuilder.spec.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,39 @@
import type { Payload } from '../../transport'
import type { InitConfiguration } from './configuration'
import { createEndpointBuilder } from './endpointBuilder'
import { validateAndBuildConfiguration } from './configuration'
import type { EndpointBuilderConfiguration } from './endpointBuilder'
import { createEndpointBuilder, createReplicaEndpointBuilder } from './endpointBuilder'

const DEFAULT_PAYLOAD = {} as Payload
const clientToken = 'some_client_token'
const configuration: EndpointBuilderConfiguration = validateAndBuildConfiguration({ clientToken })!

describe('endpointBuilder', () => {
const clientToken = 'some_client_token'
let initConfiguration: InitConfiguration

beforeEach(() => {
initConfiguration = { clientToken }
})

describe('query parameters', () => {
it('should add intake query parameters', () => {
expect(createEndpointBuilder(initConfiguration, 'rum').build('fetch', DEFAULT_PAYLOAD)).toMatch(
expect(createEndpointBuilder(configuration, 'rum').build('fetch', DEFAULT_PAYLOAD)).toMatch(
`&dd-api-key=${clientToken}&dd-evp-origin-version=(.*)&dd-evp-origin=browser&dd-request-id=(.*)`
)
})

it('should add batch_time for rum endpoint', () => {
expect(createEndpointBuilder(initConfiguration, 'rum').build('fetch', DEFAULT_PAYLOAD)).toContain('&batch_time=')
expect(createEndpointBuilder(configuration, 'rum').build('fetch', DEFAULT_PAYLOAD)).toContain('&batch_time=')
})

it('should not add batch_time for logs and replay endpoints', () => {
expect(createEndpointBuilder(initConfiguration, 'logs').build('fetch', DEFAULT_PAYLOAD)).not.toContain(
'&batch_time='
)
expect(createEndpointBuilder(initConfiguration, 'replay').build('fetch', DEFAULT_PAYLOAD)).not.toContain(
expect(createEndpointBuilder(configuration, 'logs').build('fetch', DEFAULT_PAYLOAD)).not.toContain('&batch_time=')
expect(createEndpointBuilder(configuration, 'replay').build('fetch', DEFAULT_PAYLOAD)).not.toContain(
'&batch_time='
)
})

it('should add the provided encoding', () => {
expect(
createEndpointBuilder(initConfiguration, 'rum').build('fetch', { ...DEFAULT_PAYLOAD, encoding: 'deflate' })
createEndpointBuilder(configuration, 'rum').build('fetch', { ...DEFAULT_PAYLOAD, encoding: 'deflate' })
).toContain('&dd-evp-encoding=deflate')
})

it('should not start with ddsource for internal analytics mode', () => {
const url = createEndpointBuilder({ ...initConfiguration, internalAnalyticsSubdomain: 'foo' }, 'rum').build(
const url = createEndpointBuilder({ ...configuration, internalAnalyticsSubdomain: 'foo' }, 'rum').build(
'fetch',
DEFAULT_PAYLOAD
)
Expand All @@ -49,7 +43,7 @@ describe('endpointBuilder', () => {

it('accepts extra parameters', () => {
const extraParameters = ['application.id=1234', 'application.version=1.0.0']
const url = createEndpointBuilder(initConfiguration, 'rum', extraParameters).build('fetch', DEFAULT_PAYLOAD)
const url = createEndpointBuilder(configuration, 'rum', extraParameters).build('fetch', DEFAULT_PAYLOAD)
expect(url).toContain('application.id=1234')
expect(url).toContain('application.version=1.0.0')
})
Expand All @@ -58,7 +52,7 @@ describe('endpointBuilder', () => {
describe('proxy configuration', () => {
it('should replace the intake endpoint by the proxy and set the intake path and parameters in the attribute ddforward', () => {
expect(
createEndpointBuilder({ ...initConfiguration, proxy: 'https://proxy.io/path' }, 'rum').build(
createEndpointBuilder({ ...configuration, proxy: 'https://proxy.io/path' }, 'rum').build(
'fetch',
DEFAULT_PAYLOAD
)
Expand All @@ -71,7 +65,7 @@ describe('endpointBuilder', () => {
})

it('normalizes the proxy url', () => {
const endpoint = createEndpointBuilder({ ...initConfiguration, proxy: '/path' }, 'rum').build(
const endpoint = createEndpointBuilder({ ...configuration, proxy: '/path' }, 'rum').build(
'fetch',
DEFAULT_PAYLOAD
)
Expand All @@ -82,7 +76,7 @@ describe('endpointBuilder', () => {
const proxyFn = (options: { path: string; parameters: string }) =>
`https://proxy.io/prefix${options.path}/suffix?${options.parameters}`
expect(
createEndpointBuilder({ ...initConfiguration, proxy: proxyFn }, 'rum').build('fetch', DEFAULT_PAYLOAD)
createEndpointBuilder({ ...configuration, proxy: proxyFn }, 'rum').build('fetch', DEFAULT_PAYLOAD)
).toMatch(
`https://proxy.io/prefix/api/v2/rum/suffix\\?ddsource=(.*)&dd-api-key=${clientToken}&dd-evp-origin-version=(.*)&dd-evp-origin=browser&dd-request-id=(.*)&batch_time=(.*)`
)
Expand All @@ -91,12 +85,12 @@ describe('endpointBuilder', () => {

describe('_dd attributes', () => {
it('should contain api', () => {
expect(createEndpointBuilder(initConfiguration, 'rum').build('fetch', DEFAULT_PAYLOAD)).toContain('_dd.api=fetch')
expect(createEndpointBuilder(configuration, 'rum').build('fetch', DEFAULT_PAYLOAD)).toContain('_dd.api=fetch')
})

it('should contain retry infos', () => {
expect(
createEndpointBuilder(initConfiguration, 'rum').build('fetch', {
createEndpointBuilder(configuration, 'rum').build('fetch', {
...DEFAULT_PAYLOAD,
retry: {
count: 5,
Expand All @@ -108,7 +102,7 @@ describe('endpointBuilder', () => {

it('should not contain any _dd attributes for non rum endpoints', () => {
expect(
createEndpointBuilder(initConfiguration, 'logs').build('fetch', {
createEndpointBuilder(configuration, 'logs').build('fetch', {
...DEFAULT_PAYLOAD,
retry: {
count: 5,
Expand All @@ -121,18 +115,19 @@ describe('endpointBuilder', () => {

describe('PCI compliance intake with option', () => {
it('should return PCI compliance intake endpoint if site is us1', () => {
const config: InitConfiguration & { usePciIntake?: boolean } = {
clientToken,
const config: EndpointBuilderConfiguration = {
...configuration,
usePciIntake: true,
site: 'datadoghq.com',
}

expect(createEndpointBuilder(config, 'logs').build('fetch', DEFAULT_PAYLOAD)).toContain(
'https://pci.browser-intake-datadoghq.com'
)
})
it('should not return PCI compliance intake endpoint if site is not us1', () => {
const config: InitConfiguration & { usePciIntake?: boolean } = {
clientToken,
const config: EndpointBuilderConfiguration = {
...configuration,
usePciIntake: true,
site: 'ap1.datadoghq.com',
}
Expand All @@ -141,8 +136,8 @@ describe('endpointBuilder', () => {
)
})
it('should not return PCI compliance intake endpoint if and site is us1 and track is not logs', () => {
const config: InitConfiguration & { usePciIntake?: boolean } = {
clientToken,
const config: EndpointBuilderConfiguration = {
...configuration,
usePciIntake: true,
site: 'datadoghq.com',
}
Expand All @@ -154,20 +149,45 @@ describe('endpointBuilder', () => {

describe('source configuration', () => {
it('should use the default source when no configuration is provided', () => {
const endpoint = createEndpointBuilder(initConfiguration, 'rum').build('fetch', DEFAULT_PAYLOAD)
const endpoint = createEndpointBuilder(configuration, 'rum').build('fetch', DEFAULT_PAYLOAD)
expect(endpoint).toContain('ddsource=browser')
})

it('should use flutter source when provided', () => {
const config = { ...initConfiguration, source: 'flutter' as const }
const config = { ...configuration, source: 'flutter' as const }
const endpoint = createEndpointBuilder(config, 'rum').build('fetch', DEFAULT_PAYLOAD)
expect(endpoint).toContain('ddsource=flutter')
})

it('should use unity source when provided', () => {
const config = { ...initConfiguration, source: 'unity' as const }
const config = { ...configuration, source: 'unity' as const }
const endpoint = createEndpointBuilder(config, 'rum').build('fetch', DEFAULT_PAYLOAD)
expect(endpoint).toContain('ddsource=unity')
})
})
})

describe('createReplicaEndpointBuilder', () => {
it('enforce US1 site', () => {
const endpoint = createReplicaEndpointBuilder(
{ ...configuration, site: 'datadoghq.eu' },
{ clientToken: 'replica-client-token' },
'rum'
)
expect(endpoint.build('fetch', DEFAULT_PAYLOAD)).toContain('https://browser-intake-datadoghq.com')
})

it('uses the replica client token', () => {
const endpoint = createReplicaEndpointBuilder(configuration, { clientToken: 'replica-client-token' }, 'rum')
expect(endpoint.build('fetch', DEFAULT_PAYLOAD)).toContain('replica-client-token')
})

it('adds the replica application id to the rum replica endpoint', () => {
const endpoint = createReplicaEndpointBuilder(
configuration,
{ clientToken: 'replica-client-token', applicationId: 'replica-application-id' },
'rum'
)
expect(endpoint.build('fetch', DEFAULT_PAYLOAD)).toContain('application.id=replica-application-id')
})
})
Loading