diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b70b0a9e92..ed72b2873f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- CURRENT_STAGING: staging-16
+ CURRENT_STAGING: staging-17
APP: 'browser-sdk'
CURRENT_CI_IMAGE: 63
BUILD_STABLE_REGISTRY: '486234852809.dkr.ecr.us-east-1.amazonaws.com'
@@ -140,7 +140,17 @@ build-and-lint:
- yarn build
- yarn lint
- node scripts/check-packages.js
- - node scripts/report-bundle-size/index.js
+
+test-performance:
+ extends:
+ - .base-configuration
+ - .test-allowed-branches
+ interruptible: true
+ script:
+ - yarn
+ - yarn build:bundle
+ - node ./scripts/deploy/deploy.js staging pull-request pull-request
+ - node scripts/performance/index.js
build-bundle:
extends:
@@ -211,6 +221,15 @@ check-release:
- BUILD_MODE=release yarn build
- node scripts/release/check-release.js
+check-schemas:
+ extends:
+ - .base-configuration
+ - .test-allowed-branches
+ interruptible: true
+ script:
+ - yarn
+ - node scripts/check-schemas.js
+
unit-bs:
stage: browserstack
extends:
diff --git a/Dockerfile b/Dockerfile
index e8634080b2..24d0f82629 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:20.12.1-buster-slim
+FROM node:20.12.2-buster-slim
ARG CHROME_PACKAGE_VERSION
diff --git a/developer-extension/package.json b/developer-extension/package.json
index 218114d2d1..7d50401d1e 100644
--- a/developer-extension/package.json
+++ b/developer-extension/package.json
@@ -7,23 +7,23 @@
"dev": "webpack --mode development --watch"
},
"devDependencies": {
- "@tabler/icons-react": "3.1.0",
+ "@tabler/icons-react": "3.2.0",
"@types/chrome": "0.0.266",
- "@types/react": "18.2.74",
- "@types/react-dom": "18.2.24",
+ "@types/react": "18.2.79",
+ "@types/react-dom": "18.2.25",
"@webextension-toolbox/webpack-webextension-plugin": "3.3.1",
"copy-webpack-plugin": "12.0.2",
- "css-loader": "7.1.0",
+ "css-loader": "6.11.0",
"html-webpack-plugin": "5.6.0",
- "style-loader": "3.3.4",
+ "style-loader": "4.0.0",
"webpack": "5.91.0"
},
"dependencies": {
"@datadog/browser-core": "workspace:*",
"@datadog/browser-logs": "workspace:*",
"@datadog/browser-rum": "workspace:*",
- "@mantine/core": "7.7.1",
- "@mantine/hooks": "7.7.1",
+ "@mantine/core": "7.8.0",
+ "@mantine/hooks": "7.8.0",
"clsx": "2.1.0",
"react": "18.2.0",
"react-dom": "18.2.0"
diff --git a/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx b/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx
index fac86ccf06..99daf31526 100644
--- a/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx
+++ b/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx
@@ -280,6 +280,13 @@ function TelemetryDescription({ event }: { event: TelemetryEvent }) {
if (event.telemetry.type === 'configuration') {
return Configuration
}
+ if (event.telemetry.type === 'usage') {
+ return (
+ <>
+ Usage of {event.telemetry.usage.feature}
+ >
+ )
+ }
return <>{event.telemetry.message}>
}
diff --git a/package.json b/package.json
index dfc9e5190e..850b010cfd 100644
--- a/package.json
+++ b/package.json
@@ -35,14 +35,14 @@
"@types/cors": "2.8.17",
"@types/express": "4.17.21",
"@types/jasmine": "3.10.18",
- "@typescript-eslint/eslint-plugin": "7.5.0",
- "@typescript-eslint/parser": "7.5.0",
- "@wdio/browserstack-service": "8.35.1",
- "@wdio/cli": "8.35.1",
- "@wdio/jasmine-framework": "8.35.1",
- "@wdio/junit-reporter": "8.32.4",
- "@wdio/local-runner": "8.35.1",
- "@wdio/spec-reporter": "8.32.4",
+ "@typescript-eslint/eslint-plugin": "7.7.0",
+ "@typescript-eslint/parser": "7.7.0",
+ "@wdio/browserstack-service": "8.36.0",
+ "@wdio/cli": "8.36.0",
+ "@wdio/jasmine-framework": "8.36.0",
+ "@wdio/junit-reporter": "8.36.0",
+ "@wdio/local-runner": "8.36.0",
+ "@wdio/spec-reporter": "8.36.0",
"ajv": "6.12.6",
"browserstack-local": "1.5.5",
"chrome-webstore-upload": "3.0.3",
@@ -79,8 +79,8 @@
"ts-loader": "9.5.1",
"ts-node": "10.9.2",
"tsconfig-paths-webpack-plugin": "4.1.0",
- "typescript": "5.4.4",
- "webdriverio": "8.35.1",
+ "typescript": "5.4.5",
+ "webdriverio": "8.36.0",
"webpack": "5.91.0",
"webpack-cli": "5.1.4",
"webpack-dev-middleware": "7.2.1"
@@ -90,7 +90,7 @@
"@mantine/core/type-fest": "4.15.0"
},
"volta": {
- "node": "20.12.1",
+ "node": "20.12.2",
"yarn": "1.22.22"
},
"packageManager": "yarn@3.8.1"
diff --git a/packages/core/src/domain/configuration/configuration.ts b/packages/core/src/domain/configuration/configuration.ts
index 839cc4fecc..895ba7e337 100644
--- a/packages/core/src/domain/configuration/configuration.ts
+++ b/packages/core/src/domain/configuration/configuration.ts
@@ -66,6 +66,7 @@ export interface InitConfiguration {
internalAnalyticsSubdomain?: string
telemetryConfigurationSampleRate?: number
+ telemetryUsageSampleRate?: number
}
// This type is only used to build the core configuration. Logs and RUM SDKs are using a proper type
@@ -90,6 +91,7 @@ export interface Configuration extends TransportConfiguration {
sessionSampleRate: number
telemetrySampleRate: number
telemetryConfigurationSampleRate: number
+ telemetryUsageSampleRate: number
service: string | undefined
silentMultipleInit: boolean
allowUntrustedEvents: boolean
@@ -130,6 +132,14 @@ export function validateAndBuildConfiguration(initConfiguration: InitConfigurati
return
}
+ if (
+ initConfiguration.telemetryUsageSampleRate !== undefined &&
+ !isPercentage(initConfiguration.telemetryUsageSampleRate)
+ ) {
+ display.error('Telemetry Usage Sample Rate should be a number between 0 and 100')
+ return
+ }
+
if (
initConfiguration.trackingConsent !== undefined &&
!objectHasValue(TrackingConsent, initConfiguration.trackingConsent)
@@ -155,6 +165,7 @@ export function validateAndBuildConfiguration(initConfiguration: InitConfigurati
sessionSampleRate: initConfiguration.sessionSampleRate ?? 100,
telemetrySampleRate: initConfiguration.telemetrySampleRate ?? 20,
telemetryConfigurationSampleRate: initConfiguration.telemetryConfigurationSampleRate ?? 5,
+ telemetryUsageSampleRate: initConfiguration.telemetryUsageSampleRate ?? 5,
service: initConfiguration.service,
silentMultipleInit: !!initConfiguration.silentMultipleInit,
allowUntrustedEvents: !!initConfiguration.allowUntrustedEvents,
@@ -190,6 +201,7 @@ export function serializeConfiguration(initConfiguration: InitConfiguration) {
session_sample_rate: initConfiguration.sessionSampleRate,
telemetry_sample_rate: initConfiguration.telemetrySampleRate,
telemetry_configuration_sample_rate: initConfiguration.telemetryConfigurationSampleRate,
+ telemetry_usage_sample_rate: initConfiguration.telemetryUsageSampleRate,
use_before_send: !!initConfiguration.beforeSend,
use_cross_site_session_cookie: initConfiguration.useCrossSiteSessionCookie,
use_partitioned_cross_site_session_cookie: initConfiguration.usePartitionedCrossSiteSessionCookie,
diff --git a/packages/core/src/domain/telemetry/index.ts b/packages/core/src/domain/telemetry/index.ts
index 6b1999601c..abbd10bbe2 100644
--- a/packages/core/src/domain/telemetry/index.ts
+++ b/packages/core/src/domain/telemetry/index.ts
@@ -8,6 +8,7 @@ export {
startTelemetry,
isTelemetryReplicationAllowed,
addTelemetryConfiguration,
+ addTelemetryUsage,
} from './telemetry'
export * from './rawTelemetryEvent.types'
diff --git a/packages/core/src/domain/telemetry/rawTelemetryEvent.types.ts b/packages/core/src/domain/telemetry/rawTelemetryEvent.types.ts
index 1f016805e6..663be9a253 100644
--- a/packages/core/src/domain/telemetry/rawTelemetryEvent.types.ts
+++ b/packages/core/src/domain/telemetry/rawTelemetryEvent.types.ts
@@ -1,8 +1,9 @@
-import type { TelemetryEvent, TelemetryConfigurationEvent } from './telemetryEvent.types'
+import type { TelemetryEvent, TelemetryConfigurationEvent, TelemetryUsageEvent } from './telemetryEvent.types'
export const TelemetryType = {
log: 'log',
configuration: 'configuration',
+ usage: 'usage',
} as const
export const enum StatusType {
@@ -17,3 +18,4 @@ export interface RuntimeEnvInfo {
export type RawTelemetryEvent = TelemetryEvent['telemetry']
export type RawTelemetryConfiguration = TelemetryConfigurationEvent['telemetry']['configuration']
+export type RawTelemetryUsage = TelemetryUsageEvent['telemetry']['usage']
diff --git a/packages/core/src/domain/telemetry/telemetry.spec.ts b/packages/core/src/domain/telemetry/telemetry.spec.ts
index ac52ab19f5..27befba09b 100644
--- a/packages/core/src/domain/telemetry/telemetry.spec.ts
+++ b/packages/core/src/domain/telemetry/telemetry.spec.ts
@@ -12,6 +12,7 @@ import {
scrubCustomerFrames,
formatError,
addTelemetryConfiguration,
+ addTelemetryUsage,
TelemetryService,
} from './telemetry'
@@ -72,6 +73,32 @@ describe('telemetry', () => {
})
})
+ describe('addTelemetryUsage', () => {
+ it('should collects usage when sampled', () => {
+ const { notifySpy } = startAndSpyTelemetry({ telemetrySampleRate: 100, telemetryUsageSampleRate: 100 })
+
+ addTelemetryUsage({ feature: 'set-tracking-consent', tracking_consent: 'granted' })
+
+ expect(notifySpy).toHaveBeenCalled()
+ })
+
+ it('should not notify usage when not sampled', () => {
+ const { notifySpy } = startAndSpyTelemetry({ telemetrySampleRate: 100, telemetryUsageSampleRate: 0 })
+
+ addTelemetryUsage({ feature: 'set-tracking-consent', tracking_consent: 'granted' })
+
+ expect(notifySpy).not.toHaveBeenCalled()
+ })
+
+ it('should not notify usage when telemetrySampleRate is 0', () => {
+ const { notifySpy } = startAndSpyTelemetry({ telemetrySampleRate: 0, telemetryUsageSampleRate: 100 })
+
+ addTelemetryUsage({ feature: 'set-tracking-consent', tracking_consent: 'granted' })
+
+ expect(notifySpy).not.toHaveBeenCalled()
+ })
+ })
+
it('should contains feature flags', () => {
addExperimentalFeatures(['foo' as ExperimentalFeature])
const { notifySpy } = startAndSpyTelemetry()
diff --git a/packages/core/src/domain/telemetry/telemetry.ts b/packages/core/src/domain/telemetry/telemetry.ts
index dae8c490ae..c34bc9d98c 100644
--- a/packages/core/src/domain/telemetry/telemetry.ts
+++ b/packages/core/src/domain/telemetry/telemetry.ts
@@ -17,7 +17,12 @@ import type { StackTrace } from '../error/computeStackTrace'
import { computeStackTrace } from '../error/computeStackTrace'
import { getConnectivity } from '../connectivity'
import type { TelemetryEvent } from './telemetryEvent.types'
-import type { RawTelemetryConfiguration, RawTelemetryEvent, RuntimeEnvInfo } from './rawTelemetryEvent.types'
+import type {
+ RawTelemetryConfiguration,
+ RawTelemetryEvent,
+ RuntimeEnvInfo,
+ RawTelemetryUsage,
+} from './rawTelemetryEvent.types'
import { StatusType, TelemetryType } from './rawTelemetryEvent.types'
// replaced at build time
@@ -48,9 +53,10 @@ const TELEMETRY_EXCLUDED_SITES: string[] = [INTAKE_SITE_US1_FED]
const telemetryConfiguration: {
maxEventsPerPage: number
sentEventCount: number
- telemetryEnabled: boolean
- telemetryConfigurationEnabled: boolean
-} = { maxEventsPerPage: 0, sentEventCount: 0, telemetryEnabled: false, telemetryConfigurationEnabled: false }
+} = {
+ maxEventsPerPage: 0,
+ sentEventCount: 0,
+}
let onRawTelemetryEventCollected: ((event: RawTelemetryEvent) => void) | undefined
@@ -58,14 +64,18 @@ export function startTelemetry(telemetryService: TelemetryService, configuration
let contextProvider: () => Context
const observable = new Observable()
- telemetryConfiguration.telemetryEnabled =
+ const telemetryEnabled =
!includes(TELEMETRY_EXCLUDED_SITES, configuration.site) && performDraw(configuration.telemetrySampleRate)
- telemetryConfiguration.telemetryConfigurationEnabled =
- telemetryConfiguration.telemetryEnabled && performDraw(configuration.telemetryConfigurationSampleRate)
+
+ const telemetryEnabledPerType = {
+ [TelemetryType.log]: telemetryEnabled,
+ [TelemetryType.configuration]: telemetryEnabled && performDraw(configuration.telemetryConfigurationSampleRate),
+ [TelemetryType.usage]: telemetryEnabled && performDraw(configuration.telemetryUsageSampleRate),
+ }
const runtimeEnvInfo = getRuntimeEnvInfo()
onRawTelemetryEventCollected = (rawEvent: RawTelemetryEvent) => {
- if (telemetryConfiguration.telemetryEnabled) {
+ if (telemetryEnabledPerType[rawEvent.type!]) {
const event = toTelemetryEvent(telemetryService, rawEvent, runtimeEnvInfo)
observable.notify(event)
sendToExtension('telemetry', event)
@@ -108,7 +118,7 @@ export function startTelemetry(telemetryService: TelemetryService, configuration
contextProvider = provider
},
observable,
- enabled: telemetryConfiguration.telemetryEnabled,
+ enabled: telemetryEnabled,
}
}
function getRuntimeEnvInfo(): RuntimeEnvInfo {
@@ -172,12 +182,17 @@ export function addTelemetryError(e: unknown, context?: Context) {
}
export function addTelemetryConfiguration(configuration: RawTelemetryConfiguration) {
- if (telemetryConfiguration.telemetryConfigurationEnabled) {
- addTelemetry({
- type: TelemetryType.configuration,
- configuration,
- })
- }
+ addTelemetry({
+ type: TelemetryType.configuration,
+ configuration,
+ })
+}
+
+export function addTelemetryUsage(usage: RawTelemetryUsage) {
+ addTelemetry({
+ type: TelemetryType.usage,
+ usage,
+ })
}
function addTelemetry(event: RawTelemetryEvent) {
diff --git a/packages/core/src/domain/telemetry/telemetryEvent.types.ts b/packages/core/src/domain/telemetry/telemetryEvent.types.ts
index cb0fc2e50e..b389f1d7d2 100644
--- a/packages/core/src/domain/telemetry/telemetryEvent.types.ts
+++ b/packages/core/src/domain/telemetry/telemetryEvent.types.ts
@@ -6,7 +6,11 @@
/**
* Schema of all properties of a telemetry event
*/
-export type TelemetryEvent = TelemetryErrorEvent | TelemetryDebugEvent | TelemetryConfigurationEvent
+export type TelemetryEvent =
+ | TelemetryErrorEvent
+ | TelemetryDebugEvent
+ | TelemetryConfigurationEvent
+ | TelemetryUsageEvent
/**
* Schema of all properties of a telemetry error event
*/
@@ -97,6 +101,10 @@ export type TelemetryConfigurationEvent = CommonTelemetryProperties & {
* The percentage of telemetry configuration events sent after being sampled by telemetry_sample_rate
*/
telemetry_configuration_sample_rate?: number
+ /**
+ * The percentage of telemetry usage events sent after being sampled by telemetry_sample_rate
+ */
+ telemetry_usage_sample_rate?: number
/**
* The percentage of requests traced
*/
@@ -120,7 +128,7 @@ export type TelemetryConfigurationEvent = CommonTelemetryProperties & {
/**
* The initial tracking consent value
*/
- tracking_consent?: string
+ tracking_consent?: 'granted' | 'not-granted' | 'pending'
/**
* Whether the session replay start is handled manually
*/
@@ -351,6 +359,55 @@ export type TelemetryConfigurationEvent = CommonTelemetryProperties & {
}
[k: string]: unknown
}
+/**
+ * Schema of all properties of a telemetry usage event
+ */
+export type TelemetryUsageEvent = CommonTelemetryProperties & {
+ /**
+ * The telemetry usage information
+ */
+ telemetry: {
+ /**
+ * Telemetry type
+ */
+ type: 'usage'
+ usage: TelemetryCommonFeaturesUsage | TelemetryBrowserFeaturesUsage
+ [k: string]: unknown
+ }
+ [k: string]: unknown
+}
+/**
+ * Schema of features usage common across SDKs
+ */
+export type TelemetryCommonFeaturesUsage =
+ | {
+ /**
+ * setTrackingConsent API
+ */
+ feature: 'set-tracking-consent'
+ /**
+ * The tracking consent value set by the user
+ */
+ tracking_consent: 'granted' | 'not-granted' | 'pending'
+ [k: string]: unknown
+ }
+ | {
+ /**
+ * stopSession API
+ */
+ feature: 'stop-session'
+ [k: string]: unknown
+ }
+/**
+ * Schema of browser specific features usage
+ */
+export type TelemetryBrowserFeaturesUsage = {
+ /**
+ * startSessionReplayRecording API
+ */
+ feature: 'start-session-replay-recording'
+ [k: string]: unknown
+}
/**
* Schema of common properties of Telemetry events
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index cbd049e324..dd39171ee0 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -40,6 +40,7 @@ export {
TelemetryService,
isTelemetryReplicationAllowed,
addTelemetryConfiguration,
+ addTelemetryUsage,
} from './domain/telemetry'
export { monitored, monitor, callMonitored, setDebugMode } from './tools/monitor'
export { Observable, Subscription } from './tools/observable'
diff --git a/packages/core/test/coreConfiguration.ts b/packages/core/test/coreConfiguration.ts
index 9c32befc3f..a81216aa96 100644
--- a/packages/core/test/coreConfiguration.ts
+++ b/packages/core/test/coreConfiguration.ts
@@ -35,12 +35,14 @@ export const EXHAUSTIVE_INIT_CONFIGURATION: Required = {
datacenter: 'datacenter',
internalAnalyticsSubdomain: 'internal-analytics-subdomain.com',
telemetryConfigurationSampleRate: 70,
+ telemetryUsageSampleRate: 80,
}
export const SERIALIZED_EXHAUSTIVE_INIT_CONFIGURATION = {
session_sample_rate: 50,
telemetry_sample_rate: 60,
telemetry_configuration_sample_rate: 70,
+ telemetry_usage_sample_rate: 80,
use_before_send: true,
use_cross_site_session_cookie: true,
use_partitioned_cross_site_session_cookie: true,
@@ -51,7 +53,7 @@ export const SERIALIZED_EXHAUSTIVE_INIT_CONFIGURATION = {
allow_fallback_to_local_storage: true,
store_contexts_across_pages: true,
allow_untrusted_events: true,
- tracking_consent: 'not-granted',
+ tracking_consent: 'not-granted' as const,
}
/**
diff --git a/packages/logs/src/boot/logsPublicApi.ts b/packages/logs/src/boot/logsPublicApi.ts
index 77a0e86f83..83e8ad076b 100644
--- a/packages/logs/src/boot/logsPublicApi.ts
+++ b/packages/logs/src/boot/logsPublicApi.ts
@@ -1,5 +1,6 @@
import type { Context, TrackingConsent, User } from '@datadog/browser-core'
import {
+ addTelemetryUsage,
CustomerDataType,
assign,
createContextManager,
@@ -86,7 +87,10 @@ export function makeLogsPublicApi(startLogsImpl: StartLogs) {
* If this method is called before the init() method, the provided value will take precedence
* over the one provided as initialization parameter.
*/
- setTrackingConsent: monitor((trackingConsent: TrackingConsent) => trackingConsentState.update(trackingConsent)),
+ setTrackingConsent: monitor((trackingConsent: TrackingConsent) => {
+ trackingConsentState.update(trackingConsent)
+ addTelemetryUsage({ feature: 'set-tracking-consent', tracking_consent: trackingConsent })
+ }),
getGlobalContext: monitor(() => globalContextManager.getContext()),
diff --git a/packages/rum-core/src/boot/rumPublicApi.ts b/packages/rum-core/src/boot/rumPublicApi.ts
index e88333ecd3..45619ab18b 100644
--- a/packages/rum-core/src/boot/rumPublicApi.ts
+++ b/packages/rum-core/src/boot/rumPublicApi.ts
@@ -9,6 +9,7 @@ import type {
TrackingConsent,
} from '@datadog/browser-core'
import {
+ addTelemetryUsage,
timeStampToClocks,
isExperimentalFeatureEnabled,
ExperimentalFeature,
@@ -204,7 +205,10 @@ export function makeRumPublicApi(startRumImpl: StartRum, recorderApi: RecorderAp
* If this method is called before the init() method, the provided value will take precedence
* over the one provided as initialization parameter.
*/
- setTrackingConsent: monitor((trackingConsent: TrackingConsent) => trackingConsentState.update(trackingConsent)),
+ setTrackingConsent: monitor((trackingConsent: TrackingConsent) => {
+ trackingConsentState.update(trackingConsent)
+ addTelemetryUsage({ feature: 'set-tracking-consent', tracking_consent: trackingConsent })
+ }),
setGlobalContextProperty: monitor((key, value) => globalContextManager.setContextProperty(key, value)),
@@ -278,6 +282,7 @@ export function makeRumPublicApi(startRumImpl: StartRum, recorderApi: RecorderAp
stopSession: monitor(() => {
strategy.stopSession()
+ addTelemetryUsage({ feature: 'stop-session' })
}),
/**
@@ -288,7 +293,10 @@ export function makeRumPublicApi(startRumImpl: StartRum, recorderApi: RecorderAp
}),
getSessionReplayLink: monitor(() => recorderApi.getSessionReplayLink()),
- startSessionReplayRecording: monitor(() => recorderApi.start()),
+ startSessionReplayRecording: monitor(() => {
+ recorderApi.start()
+ addTelemetryUsage({ feature: 'start-session-replay-recording' })
+ }),
stopSessionReplayRecording: monitor(() => recorderApi.stop()),
})
diff --git a/packages/rum/src/domain/record/record.spec.ts b/packages/rum/src/domain/record/record.spec.ts
index f13b824838..1e36b26c0d 100644
--- a/packages/rum/src/domain/record/record.spec.ts
+++ b/packages/rum/src/domain/record/record.spec.ts
@@ -3,7 +3,7 @@ import type { RumConfiguration, ViewCreatedEvent } from '@datadog/browser-rum-co
import { LifeCycle, LifeCycleEventType } from '@datadog/browser-rum-core'
import type { Clock } from '@datadog/browser-core/test'
import { createNewEvent, collectAsyncCalls } from '@datadog/browser-core/test'
-import { findFullSnapshot, findNode, recordsPerFullSnapshot } from '../../../test'
+import { findElement, findFullSnapshot, findNode, recordsPerFullSnapshot } from '../../../test'
import type {
BrowserIncrementalSnapshotRecord,
BrowserMutationData,
@@ -11,6 +11,7 @@ import type {
DocumentFragmentNode,
ElementNode,
FocusRecord,
+ ScrollData,
} from '../../types'
import { NodeType, RecordType, IncrementalSource } from '../../types'
import { appendElement } from '../../../../rum-core/test'
@@ -334,6 +335,28 @@ describe('record', () => {
expect(inputRecords.length).toBe(1)
})
+ it('should record the scroll event inside a shadow root', () => {
+ const div = appendElement('', createShadow()) as HTMLDivElement
+ startRecording()
+ expect(getEmittedRecords().length).toBe(recordsPerFullSnapshot())
+
+ div.dispatchEvent(createNewEvent('scroll', { target: div, composed: false }))
+
+ recordApi.flushMutations()
+
+ const scrollRecords = getEmittedRecords().filter(
+ (record) => record.type === RecordType.IncrementalSnapshot && record.data.source === IncrementalSource.Scroll
+ )
+ expect(scrollRecords.length).toBe(1)
+
+ const scrollData = getLastIncrementalSnapshotData(getEmittedRecords(), IncrementalSource.Scroll)
+
+ const fs = findFullSnapshot({ records: getEmittedRecords() })!
+ const scrollableNode = findElement(fs.data.node, (node) => node.attributes['unique-selector'] === 'enabled')!
+
+ expect(scrollData.id).toBe(scrollableNode.id)
+ })
+
it('should clean the state once the shadow dom is removed to avoid memory leak', () => {
const shadowRoot = createShadow()
appendElement('', shadowRoot)
diff --git a/packages/rum/src/domain/record/record.ts b/packages/rum/src/domain/record/record.ts
index fd156cdaba..f5b027d1ea 100644
--- a/packages/rum/src/domain/record/record.ts
+++ b/packages/rum/src/domain/record/record.ts
@@ -51,10 +51,7 @@ export function record(options: RecordOptions): RecordAPI {
const elementsScrollPositions = createElementsScrollPositions()
- const shadowRootsController = initShadowRootsController(configuration, {
- mutationCb: emitAndComputeStats,
- inputCb: emitAndComputeStats,
- })
+ const shadowRootsController = initShadowRootsController(configuration, emitAndComputeStats, elementsScrollPositions)
const { stop: stopFullSnapshots } = startFullSnapshots(
elementsScrollPositions,
@@ -76,7 +73,7 @@ export function record(options: RecordOptions): RecordAPI {
mutationTracker,
trackMove(configuration, emitAndComputeStats),
trackMouseInteraction(configuration, emitAndComputeStats, recordIds),
- trackScroll(configuration, emitAndComputeStats, elementsScrollPositions),
+ trackScroll(configuration, emitAndComputeStats, elementsScrollPositions, document),
trackViewportResize(configuration, emitAndComputeStats),
trackInput(configuration, emitAndComputeStats),
trackMediaInteraction(configuration, emitAndComputeStats),
diff --git a/packages/rum/src/domain/record/serialization/serializeAttribute.spec.ts b/packages/rum/src/domain/record/serialization/serializeAttribute.spec.ts
index 6034ca5199..5163bb2ee7 100644
--- a/packages/rum/src/domain/record/serialization/serializeAttribute.spec.ts
+++ b/packages/rum/src/domain/record/serialization/serializeAttribute.spec.ts
@@ -144,4 +144,13 @@ describe('serializeAttribute', () => {
)
})
})
+
+ describe('iframe srcdoc masking', () => {
+ it('should mask the srcdoc when privacy override set to mask', () => {
+ const node = document.createElement('iframe')
+ node.srcdoc = 'data-foo">'
+ node.setAttribute(PRIVACY_ATTR_NAME, 'mask')
+ expect(serializeAttribute(node, NodePrivacyLevel.MASK, 'srcdoc', DEFAULT_CONFIGURATION)).toBe('***')
+ })
+ })
})
diff --git a/packages/rum/src/domain/record/serialization/serializeAttribute.ts b/packages/rum/src/domain/record/serialization/serializeAttribute.ts
index 4c6991c5e1..dcbbcfc65b 100644
--- a/packages/rum/src/domain/record/serialization/serializeAttribute.ts
+++ b/packages/rum/src/domain/record/serialization/serializeAttribute.ts
@@ -68,6 +68,11 @@ export function serializeAttribute(
// Exception: it's safe to reveal the `${PRIVACY_ATTR_NAME}` attr
return CENSORED_STRING_MARK
}
+
+ // mask iframe srcdoc
+ if (tagName === 'IFRAME' && attributeName === 'srcdoc') {
+ return CENSORED_STRING_MARK
+ }
}
if (!attributeValue || typeof attributeValue !== 'string') {
diff --git a/packages/rum/src/domain/record/shadowRootsController.ts b/packages/rum/src/domain/record/shadowRootsController.ts
index 5a5ad60125..d505b19b84 100644
--- a/packages/rum/src/domain/record/shadowRootsController.ts
+++ b/packages/rum/src/domain/record/shadowRootsController.ts
@@ -1,6 +1,7 @@
import type { RumConfiguration } from '@datadog/browser-rum-core'
-import type { InputCallback, MutationCallBack } from './trackers'
-import { trackInput, trackMutation } from './trackers'
+import type { BrowserIncrementalSnapshotRecord } from '../../types'
+import { trackInput, trackMutation, trackScroll } from './trackers'
+import type { ElementsScrollPositions } from './elementsScrollPositions'
interface ShadowRootController {
stop: () => void
@@ -18,13 +19,8 @@ export interface ShadowRootsController {
export const initShadowRootsController = (
configuration: RumConfiguration,
- {
- mutationCb,
- inputCb,
- }: {
- mutationCb: MutationCallBack
- inputCb: InputCallback
- }
+ callback: (record: BrowserIncrementalSnapshotRecord) => void,
+ elementsScrollPositions: ElementsScrollPositions
): ShadowRootsController => {
const controllerByShadowRoot = new Map()
@@ -33,14 +29,17 @@ export const initShadowRootsController = (
if (controllerByShadowRoot.has(shadowRoot)) {
return
}
- const mutationTracker = trackMutation(mutationCb, configuration, shadowRootsController, shadowRoot)
- // the change event no do bubble up across the shadow root, we have to listen on the shadow root
- const inputTracker = trackInput(configuration, inputCb, shadowRoot)
+ const mutationTracker = trackMutation(callback, configuration, shadowRootsController, shadowRoot)
+ // The change event does not bubble up across the shadow root, we have to listen on the shadow root
+ const inputTracker = trackInput(configuration, callback, shadowRoot)
+ // The scroll event does not bubble up across the shadow root, we have to listen on the shadow root
+ const scrollTracker = trackScroll(configuration, callback, elementsScrollPositions, shadowRoot)
controllerByShadowRoot.set(shadowRoot, {
flush: () => mutationTracker.flush(),
stop: () => {
mutationTracker.stop()
inputTracker.stop()
+ scrollTracker.stop()
},
})
},
diff --git a/packages/rum/src/domain/record/trackers/index.ts b/packages/rum/src/domain/record/trackers/index.ts
index e0ef802644..4a4fb792f4 100644
--- a/packages/rum/src/domain/record/trackers/index.ts
+++ b/packages/rum/src/domain/record/trackers/index.ts
@@ -8,5 +8,6 @@ export { trackFocus } from './trackFocus'
export { trackFrustration } from './trackFrustration'
export { trackViewEnd } from './trackViewEnd'
export { InputCallback, trackInput } from './trackInput'
+export { ScrollCallback } from './trackScroll'
export { trackMutation, MutationCallBack, RumMutationRecord } from './trackMutation'
export { Tracker } from './types'
diff --git a/packages/rum/src/domain/record/trackers/trackScroll.ts b/packages/rum/src/domain/record/trackers/trackScroll.ts
index df00846722..28aa1ac25e 100644
--- a/packages/rum/src/domain/record/trackers/trackScroll.ts
+++ b/packages/rum/src/domain/record/trackers/trackScroll.ts
@@ -16,7 +16,8 @@ export type ScrollCallback = (incrementalSnapshotRecord: BrowserIncrementalSnaps
export function trackScroll(
configuration: RumConfiguration,
scrollCb: ScrollCallback,
- elementsScrollPositions: ElementsScrollPositions
+ elementsScrollPositions: ElementsScrollPositions,
+ target: Document | ShadowRoot = document
): Tracker {
const { throttled: updatePosition, cancel: cancelThrottle } = throttle((event: Event) => {
const target = getEventTarget(event) as HTMLElement | Document
@@ -48,7 +49,7 @@ export function trackScroll(
)
}, SCROLL_OBSERVER_THRESHOLD)
- const { stop: removeListener } = addEventListener(configuration, document, DOM_EVENT.SCROLL, updatePosition, {
+ const { stop: removeListener } = addEventListener(configuration, target, DOM_EVENT.SCROLL, updatePosition, {
capture: true,
passive: true,
})
diff --git a/performances/package.json b/performances/package.json
index 72e40d4c46..988552f535 100644
--- a/performances/package.json
+++ b/performances/package.json
@@ -6,10 +6,10 @@
"start": "ts-node ./src/main.ts"
},
"dependencies": {
- "@types/node": "20.12.5",
+ "@types/node": "20.12.7",
"@types/node-forge": "1.3.11",
"node-forge": "1.3.1",
- "puppeteer": "22.6.3",
+ "puppeteer": "22.6.5",
"ts-node": "10.9.2"
},
"volta": {
diff --git a/sandbox/index.html b/sandbox/index.html
index 6c187bffd7..20c03da615 100644
--- a/sandbox/index.html
+++ b/sandbox/index.html
@@ -14,12 +14,14 @@
trackLongTasks: true,
telemetrySampleRate: 100,
telemetryConfigurationSampleRate: 100,
+ telemetryUsageSampleRate: 100,
enableExperimentalFeatures: [],
})
DD_LOGS.init({
clientToken: 'xxx',
telemetrySampleRate: 100,
telemetryConfigurationSampleRate: 100,
+ telemetryUsageSampleRate: 100,
enableExperimentalFeatures: [],
})
diff --git a/scripts/check-schemas.js b/scripts/check-schemas.js
new file mode 100644
index 0000000000..fc96e7366b
--- /dev/null
+++ b/scripts/check-schemas.js
@@ -0,0 +1,17 @@
+const { printLog, printError, runMain } = require('./lib/execution-utils')
+const { command } = require('./lib/command')
+
+runMain(() => {
+ printLog('Regenerating schemas...')
+ command`scripts/cli build_json2type`.run()
+ command`node scripts/generate-schema-types.js`.run()
+
+ printLog('Checking untracked changes...')
+ const diff = command`git diff --color`.run()
+
+ if (diff) {
+ printLog(diff)
+ printError('\nUntracked changes detected, ensure that schemas and types are in-sync.\n')
+ process.exit(1)
+ }
+})
diff --git a/scripts/deploy/deploy.js b/scripts/deploy/deploy.js
index 0c96d738dc..b0fa7750d5 100644
--- a/scripts/deploy/deploy.js
+++ b/scripts/deploy/deploy.js
@@ -1,12 +1,15 @@
'use strict'
const { printLog, runMain } = require('../lib/execution-utils')
+const { fetchPR, LOCAL_BRANCH } = require('../lib/git-utils')
const { command } = require('../lib/command')
+
const {
buildRootUploadPath,
buildDatacenterUploadPath,
buildBundleFolder,
buildBundleFileName,
+ buildPullRequestUploadPath,
packages,
} = require('./lib/deployment-utils')
@@ -27,20 +30,27 @@ const AWS_CONFIG = {
/**
* Deploy SDK files to CDN
* Usage:
- * node deploy.js staging|prod staging|canary|vXXX root,us1,eu1,...
+ * node deploy.js staging|prod staging|canary|pull-request|vXXX root,pull-request,us1,eu1,...
*/
const env = process.argv[2]
const version = process.argv[3]
const uploadPathTypes = process.argv[4].split(',')
-runMain(() => {
+runMain(async () => {
const awsConfig = AWS_CONFIG[env]
let cloudfrontPathsToInvalidate = []
for (const { packageName } of packages) {
const bundleFolder = buildBundleFolder(packageName)
for (const uploadPathType of uploadPathTypes) {
let uploadPath
- if (uploadPathType === 'root') {
+ if (uploadPathType === 'pull-request') {
+ const pr = await fetchPR(LOCAL_BRANCH)
+ if (!pr) {
+ console.log('No pull requests found for the branch')
+ return
+ }
+ uploadPath = buildPullRequestUploadPath(packageName, pr.number)
+ } else if (uploadPathType === 'root') {
uploadPath = buildRootUploadPath(packageName, version)
} else {
uploadPath = buildDatacenterUploadPath(uploadPathType, packageName, version)
@@ -58,7 +68,9 @@ function uploadToS3(awsConfig, bundlePath, uploadPath) {
const accessToS3 = generateEnvironmentForRole(awsConfig.accountId, 'build-stable-browser-agent-artifacts-s3-write')
const browserCache =
- version === 'staging' || version === 'canary' ? 15 * ONE_MINUTE_IN_SECOND : 4 * ONE_HOUR_IN_SECOND
+ version === 'staging' || version === 'canary' || version === 'pull-request'
+ ? 15 * ONE_MINUTE_IN_SECOND
+ : 4 * ONE_HOUR_IN_SECOND
const cacheControl = `max-age=${browserCache}, s-maxage=60`
printLog(`Upload ${bundlePath} to s3://${awsConfig.bucketName}/${uploadPath}`)
diff --git a/scripts/deploy/lib/deployment-utils.js b/scripts/deploy/lib/deployment-utils.js
index 5306158b17..c26acca3f5 100644
--- a/scripts/deploy/lib/deployment-utils.js
+++ b/scripts/deploy/lib/deployment-utils.js
@@ -14,6 +14,10 @@ const buildDatacenterUploadPath = (datacenter, packageName, version, extension =
// ex: datadog-rum.js
const buildBundleFileName = (packageName, extension = 'js') => `datadog-${packageName}.${extension}`
+// ex: pull-request/2781/datadog-rum.js
+function buildPullRequestUploadPath(packageName, version, extension = 'js') {
+ return `pull-request/${version}/datadog-${packageName}.${extension}`
+}
// ex: packages/rum/bundle
const buildBundleFolder = (packageName) => `packages/${packageName}/bundle`
@@ -23,4 +27,5 @@ module.exports = {
buildDatacenterUploadPath,
buildBundleFileName,
buildBundleFolder,
+ buildPullRequestUploadPath,
}
diff --git a/scripts/lib/git-utils.js b/scripts/lib/git-utils.js
index 0c9090ccd6..b4133f3120 100644
--- a/scripts/lib/git-utils.js
+++ b/scripts/lib/git-utils.js
@@ -2,7 +2,38 @@ const os = require('os')
const fs = require('fs')
const { command } = require('../lib/command')
-const { getGithubDeployKey } = require('./secrets')
+const { getGithubDeployKey, getGithubAccessToken } = require('./secrets')
+const { fetchHandlingError } = require('./execution-utils')
+
+const GITHUB_TOKEN = getGithubAccessToken()
+
+async function fetchPR(localBranch) {
+ const response = await fetchHandlingError(
+ `https://api.github.com/repos/DataDog/browser-sdk/pulls?head=DataDog:${localBranch}`,
+ {
+ method: 'GET',
+ headers: {
+ Authorization: `token ${GITHUB_TOKEN}`,
+ },
+ }
+ )
+ const pr = response.body ? await response.json() : null
+ if (pr && pr.length > 1) {
+ throw new Error('Multiple pull requests found for the branch')
+ }
+ return pr ? pr[0] : null
+}
+
+function getLastCommonCommit(baseBranch) {
+ try {
+ command`git fetch --depth=100 origin ${baseBranch}`.run()
+ const commandOutput = command`git merge-base origin/${baseBranch} HEAD`.run()
+ // SHA commit is truncated to 8 characters as bundle sizes commit are exported in short format to logs for convenience and readability.
+ return commandOutput.trim().substring(0, 8)
+ } catch (error) {
+ throw new Error('Failed to get last common commit', { cause: error })
+ }
+}
function initGitConfig(repository) {
const homedir = os.homedir()
@@ -21,4 +52,9 @@ function initGitConfig(repository) {
module.exports = {
initGitConfig,
+ fetchPR,
+ getLastCommonCommit,
+ BASE_BRANCH: process.env.MAIN_BRANCH,
+ LOCAL_BRANCH: process.env.CI_COMMIT_REF_NAME,
+ GITHUB_TOKEN,
}
diff --git a/scripts/performance/bundle-size/compute-bundle-size.js b/scripts/performance/bundle-size/compute-bundle-size.js
new file mode 100644
index 0000000000..2cc1c722a8
--- /dev/null
+++ b/scripts/performance/bundle-size/compute-bundle-size.js
@@ -0,0 +1,29 @@
+const path = require('path')
+const fs = require('fs')
+
+const rumPath = path.join(__dirname, '../../../packages/rum/bundle/datadog-rum.js')
+const logsPath = path.join(__dirname, '../../../packages/logs/bundle/datadog-logs.js')
+const rumSlimPath = path.join(__dirname, '../../../packages/rum-slim/bundle/datadog-rum-slim.js')
+const workerPath = path.join(__dirname, '../../../packages/worker/bundle/worker.js')
+
+function getBundleSize(pathBundle) {
+ try {
+ const file = fs.statSync(pathBundle)
+ return file.size
+ } catch (error) {
+ throw new Error('Failed to get bundle size', { cause: error })
+ }
+}
+
+function calculateBundleSizes() {
+ return {
+ rum: getBundleSize(rumPath),
+ logs: getBundleSize(logsPath),
+ rum_slim: getBundleSize(rumSlimPath),
+ worker: getBundleSize(workerPath),
+ }
+}
+
+module.exports = {
+ calculateBundleSizes,
+}
diff --git a/scripts/performance/cpu-performance/compute-cpu-performance.js b/scripts/performance/cpu-performance/compute-cpu-performance.js
new file mode 100644
index 0000000000..e9a4e22b70
--- /dev/null
+++ b/scripts/performance/cpu-performance/compute-cpu-performance.js
@@ -0,0 +1,68 @@
+const { fetchHandlingError } = require('../../lib/execution-utils')
+const { getOrg2ApiKey, getOrg2AppKey } = require('../../lib/secrets')
+const { timeout } = require('../../lib/execution-utils')
+const { fetchPR, LOCAL_BRANCH } = require('../../lib/git-utils')
+const { LOCAL_COMMIT_SHA } = require('../report-as-a-pr-comment')
+const API_KEY = getOrg2ApiKey()
+const APP_KEY = getOrg2AppKey()
+const TIMEOUT_IN_MS = 10000
+const TEST_PUBLIC_ID = 'vcg-7rk-5av'
+const RETRIES_NUMBER = 6
+
+async function computeCpuPerformance() {
+ const pr = await fetchPR(LOCAL_BRANCH)
+ if (!pr) {
+ console.log('No pull requests found for the branch')
+ return
+ }
+ const resultId = await triggerSyntheticsTest(pr.number, LOCAL_COMMIT_SHA)
+ await waitForSyntheticsTestToFinish(resultId, RETRIES_NUMBER)
+}
+
+async function triggerSyntheticsTest(prNumber, commitId) {
+ const body = {
+ tests: [
+ {
+ public_id: `${TEST_PUBLIC_ID}`,
+ startUrl: `https://datadoghq.dev/browser-sdk-test-playground/performance/?prNumber=${prNumber}&commitId=${commitId}`,
+ },
+ ],
+ }
+ const url = 'https://api.datadoghq.com/api/v1/synthetics/tests/trigger/ci'
+ const response = await fetchHandlingError(url, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'DD-API-KEY': API_KEY,
+ 'DD-APPLICATION-KEY': APP_KEY,
+ },
+ body: JSON.stringify(body),
+ })
+ const data = await response.json()
+ return data.results[0].result_id
+}
+
+async function waitForSyntheticsTestToFinish(resultId, RETRIES_NUMBER) {
+ const url = `https://api.datadoghq.com/api/v1/synthetics/tests/${TEST_PUBLIC_ID}/results/${resultId}`
+ for (let i = 0; i < RETRIES_NUMBER; i++) {
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'DD-API-KEY': API_KEY,
+ 'DD-APPLICATION-KEY': APP_KEY,
+ },
+ })
+ const data = await response.json()
+ if (data.length !== 0 && data.status === 0) {
+ await timeout(TIMEOUT_IN_MS) // Wait for logs ingestion
+ return
+ }
+ await timeout(TIMEOUT_IN_MS)
+ }
+ throw new Error('Synthetics test did not finish within the specified number of retries')
+}
+
+module.exports = {
+ computeCpuPerformance,
+}
diff --git a/scripts/performance/fetch-performance-metrics.js b/scripts/performance/fetch-performance-metrics.js
new file mode 100644
index 0000000000..8a59b5d902
--- /dev/null
+++ b/scripts/performance/fetch-performance-metrics.js
@@ -0,0 +1,43 @@
+const { getOrg2ApiKey, getOrg2AppKey } = require('../lib/secrets')
+const { fetchHandlingError } = require('../lib/execution-utils')
+const ONE_DAY_IN_SECOND = 24 * 60 * 60
+
+function fetchPerformanceMetrics(type, names, commitId) {
+ return Promise.all(names.map((name) => fetchMetric(type, name, commitId)))
+}
+
+async function fetchMetric(type, name, commitId) {
+ const now = Math.floor(Date.now() / 1000)
+ const date = now - 30 * ONE_DAY_IN_SECOND
+ let query = ''
+
+ if (type === 'bundle') {
+ query = `avg:bundle_sizes.${name}{commit:${commitId}}&from=${date}&to=${now}`
+ } else if (type === 'cpu') {
+ query = `avg:cpu.sdk.${name}.performance.average{commitid:${commitId}}&from=${date}&to=${now}`
+ }
+
+ const response = await fetchHandlingError(`https://api.datadoghq.com/api/v1/query?query=${query}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'DD-API-KEY': getOrg2ApiKey(),
+ 'DD-APPLICATION-KEY': getOrg2AppKey(),
+ },
+ })
+ const data = await response.json()
+ if (data.series && data.series.length > 0 && data.series[0].pointlist && data.series[0].pointlist.length > 0) {
+ return {
+ name,
+ value: data.series[0].pointlist[0][1],
+ }
+ }
+ return {
+ name,
+ value: null,
+ }
+}
+
+module.exports = {
+ fetchPerformanceMetrics,
+}
diff --git a/scripts/performance/index.js b/scripts/performance/index.js
new file mode 100644
index 0000000000..8ff5d103b3
--- /dev/null
+++ b/scripts/performance/index.js
@@ -0,0 +1,12 @@
+const { runMain } = require('../lib/execution-utils')
+const { reportAsPrComment } = require('./report-as-a-pr-comment')
+const { reportToDatadog } = require('./report-to-datadog')
+const { calculateBundleSizes } = require('./bundle-size/compute-bundle-size')
+const { computeCpuPerformance } = require('./cpu-performance/compute-cpu-performance')
+
+runMain(async () => {
+ const localBundleSizes = calculateBundleSizes()
+ await computeCpuPerformance()
+ await reportToDatadog(localBundleSizes)
+ await reportAsPrComment(localBundleSizes)
+})
diff --git a/scripts/performance/report-as-a-pr-comment.js b/scripts/performance/report-as-a-pr-comment.js
new file mode 100644
index 0000000000..1f66d7e4fe
--- /dev/null
+++ b/scripts/performance/report-as-a-pr-comment.js
@@ -0,0 +1,170 @@
+const { command } = require('../lib/command')
+const { fetchHandlingError } = require('../lib/execution-utils')
+const { LOCAL_BRANCH, BASE_BRANCH, GITHUB_TOKEN, getLastCommonCommit, fetchPR } = require('../lib/git-utils')
+const { fetchPerformanceMetrics } = require('./fetch-performance-metrics')
+const PR_COMMENT_HEADER = 'Bundles Sizes Evolution'
+const PR_COMMENTER_AUTH_TOKEN = command`authanywhere`.run().split(' ')[2].trim()
+// The value is set to 5% as it's around 10 times the average value for small PRs.
+const SIZE_INCREASE_THRESHOLD = 5
+const LOCAL_COMMIT_SHA = process.env.CI_COMMIT_SHORT_SHA
+const ACTION_NAMES = [
+ 'adderror',
+ 'addaction',
+ 'logmessage',
+ 'startview',
+ 'startstopsessionreplayrecording',
+ 'addtiming',
+ 'addglobalcontext',
+]
+
+async function reportAsPrComment(localBundleSizes) {
+ const lastCommonCommit = getLastCommonCommit(BASE_BRANCH, LOCAL_BRANCH)
+ const pr = await fetchPR(LOCAL_BRANCH)
+ if (!pr) {
+ console.log('No pull requests found for the branch')
+ return
+ }
+ const packageNames = Object.keys(localBundleSizes)
+ const baseBundleSizes = await fetchPerformanceMetrics('bundle', packageNames, lastCommonCommit)
+ const cpuBasePerformance = await fetchPerformanceMetrics('cpu', ACTION_NAMES, lastCommonCommit)
+ const cpuLocalPerformance = await fetchPerformanceMetrics('cpu', ACTION_NAMES, LOCAL_COMMIT_SHA)
+ const differenceBundle = compare(baseBundleSizes, localBundleSizes)
+ const differenceCpu = compare(cpuBasePerformance, cpuLocalPerformance)
+ const commentId = await retrieveExistingCommentId(pr.number)
+ const message = createMessage(
+ differenceBundle,
+ differenceCpu,
+ baseBundleSizes,
+ localBundleSizes,
+ cpuBasePerformance,
+ cpuLocalPerformance
+ )
+ await updateOrAddComment(message, pr.number, commentId)
+}
+
+function compare(baseResults, localResults) {
+ return baseResults.map((baseResult) => {
+ let localResult = null
+
+ if (Array.isArray(localResults)) {
+ const localResultObj = localResults.find((result) => result.name === baseResult.name)
+ localResult = localResultObj ? localResultObj.value : null
+ } else {
+ localResult = localResults[baseResult.name]
+ }
+
+ let change = null
+ let percentageChange = null
+
+ if (baseResult.value && localResult) {
+ change = localResult - baseResult.value
+ percentageChange = ((change / baseResult.value) * 100).toFixed(2)
+ } else if (localResult) {
+ change = localResult
+ percentageChange = 'N/A'
+ }
+
+ return {
+ name: baseResult.name,
+ change,
+ percentageChange,
+ }
+ })
+}
+
+async function retrieveExistingCommentId(prNumber) {
+ const response = await fetchHandlingError(
+ `https://api.github.com/repos/DataDog/browser-sdk/issues/${prNumber}/comments`,
+ {
+ method: 'GET',
+ headers: {
+ Authorization: `token ${GITHUB_TOKEN}`,
+ },
+ }
+ )
+ const comments = await response.json()
+ const targetComment = comments.find((comment) => comment.body.startsWith(`## ${PR_COMMENT_HEADER}`))
+ if (targetComment !== undefined) {
+ return targetComment.id
+ }
+}
+async function updateOrAddComment(message, prNumber, commentId) {
+ const method = commentId ? 'PATCH' : 'POST'
+ const payload = {
+ pr_url: `https://github.com/DataDog/browser-sdk/pull/${prNumber}`,
+ message,
+ header: PR_COMMENT_HEADER,
+ org: 'DataDog',
+ repo: 'browser-sdk',
+ }
+ await fetchHandlingError('https://pr-commenter.us1.ddbuild.io/internal/cit/pr-comment', {
+ method,
+ headers: {
+ Authorization: `Bearer ${PR_COMMENTER_AUTH_TOKEN}`,
+ },
+ body: JSON.stringify(payload),
+ })
+}
+
+function createMessage(
+ differenceBundle,
+ differenceCpu,
+ baseBundleSizes,
+ localBundleSizes,
+ cpuBasePerformance,
+ cpuLocalPerformance
+) {
+ let message =
+ '| š¦ Bundle Name| Base Size | Local Size | š« | š«% | Status |\n| --- | --- | --- | --- | --- | :---: |\n'
+ let highIncreaseDetected = false
+ differenceBundle.forEach((diff, index) => {
+ const baseSize = formatSize(baseBundleSizes[index].value)
+ const localSize = formatSize(localBundleSizes[diff.name])
+ const diffSize = formatSize(diff.change)
+ const sign = diff.percentageChange > 0 ? '+' : ''
+ let status = 'ā
'
+ if (diff.percentageChange > SIZE_INCREASE_THRESHOLD) {
+ status = 'ā ļø'
+ highIncreaseDetected = true
+ }
+ message += `| ${formatBundleName(diff.name)} | ${baseSize} | ${localSize} | ${diffSize} | ${sign}${diff.percentageChange}% | ${status} |\n`
+ })
+
+ if (highIncreaseDetected) {
+ message += `\nā ļø The increase is particularly high and exceeds ${SIZE_INCREASE_THRESHOLD}%. Please check the changes.`
+ }
+ message += '\n\n\nš CPU Performance
\n\n\n'
+ message +=
+ '| Action Name | Base Average Cpu Time (ms) | Local Average Cpu Time (ms) | š« |\n| --- | --- | --- | --- |\n'
+ cpuBasePerformance.forEach((cpuActionPerformance, index) => {
+ const localCpuPerf = cpuLocalPerformance[index]
+ const diffCpuPerf = differenceCpu[index]
+ const baseCpuTaskValue = cpuActionPerformance.value !== null ? cpuActionPerformance.value.toFixed(3) : 'N/A'
+ const localCpuTaskValue = localCpuPerf.value !== null ? localCpuPerf.value.toFixed(3) : 'N/A'
+ const diffCpuTaskValue = diffCpuPerf.change !== null ? diffCpuPerf.change.toFixed(3) : 'N/A'
+ message += `| ${cpuActionPerformance.name} | ${baseCpuTaskValue} | ${localCpuTaskValue} | ${diffCpuTaskValue} |\n`
+ })
+ message += '\n \n'
+
+ return message
+}
+
+function formatBundleName(bundleName) {
+ return bundleName
+ .split('_')
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ')
+}
+
+function formatSize(bytes) {
+ if (bytes < 1024) {
+ return `${bytes} B`
+ }
+
+ return `${(bytes / 1024).toFixed(2)} KiB`
+}
+
+module.exports = {
+ LOCAL_COMMIT_SHA,
+ reportAsPrComment,
+}
diff --git a/scripts/report-bundle-size/report-to-datadog.js b/scripts/performance/report-to-datadog.js
similarity index 90%
rename from scripts/report-bundle-size/report-to-datadog.js
rename to scripts/performance/report-to-datadog.js
index 0e83b24e12..9c99dc3363 100644
--- a/scripts/report-bundle-size/report-to-datadog.js
+++ b/scripts/performance/report-to-datadog.js
@@ -1,14 +1,13 @@
const { fetchHandlingError } = require('../lib/execution-utils')
const { getOrg2ApiKey } = require('../lib/secrets')
const { browserSdkVersion } = require('../lib/browser-sdk-version')
-
const LOG_INTAKE_URL = 'https://http-intake.logs.datadoghq.com/api/v2/logs'
const LOG_INTAKE_REQUEST_HEADERS = {
'DD-API-KEY': getOrg2ApiKey(),
'Content-Type': 'application/json',
}
-async function reportBundleSizesToDatadog(bundleSizes) {
+async function reportToDatadog(bundleSizes) {
const logData = createLogData(bundleSizes, browserSdkVersion)
await sendLogToOrg2(logData)
}
@@ -27,7 +26,6 @@ function createLogData(bundleSizes, browserSdkVersion) {
},
]
}
-
async function sendLogToOrg2(bundleData = {}) {
await fetchHandlingError(LOG_INTAKE_URL, {
method: 'POST',
@@ -36,4 +34,6 @@ async function sendLogToOrg2(bundleData = {}) {
})
}
-module.exports = { reportBundleSizesToDatadog }
+module.exports = {
+ reportToDatadog,
+}
diff --git a/scripts/report-bundle-size/index.js b/scripts/report-bundle-size/index.js
deleted file mode 100644
index dab2160943..0000000000
--- a/scripts/report-bundle-size/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const path = require('path')
-const fs = require('fs')
-const { runMain } = require('../lib/execution-utils')
-const { reportBundleSizesAsPrComment } = require('./report-as-a-pr-comment')
-const { reportBundleSizesToDatadog } = require('./report-to-datadog')
-
-const rumPath = path.join(__dirname, '../../packages/rum/bundle/datadog-rum.js')
-const logsPath = path.join(__dirname, '../../packages/logs/bundle/datadog-logs.js')
-const rumSlimPath = path.join(__dirname, '../../packages/rum-slim/bundle/datadog-rum-slim.js')
-const workerPath = path.join(__dirname, '../../packages/worker/bundle/worker.js')
-
-runMain(async () => {
- const bundleSizes = {
- rum: getBundleSize(rumPath),
- logs: getBundleSize(logsPath),
- rum_slim: getBundleSize(rumSlimPath),
- worker: getBundleSize(workerPath),
- }
- await reportBundleSizesToDatadog(bundleSizes)
- await reportBundleSizesAsPrComment(bundleSizes)
-})
-
-function getBundleSize(pathBundle) {
- try {
- const file = fs.statSync(pathBundle)
- return file.size
- } catch (error) {
- throw new Error('Failed to get bundle size', { cause: error })
- }
-}
diff --git a/scripts/report-bundle-size/report-as-a-pr-comment.js b/scripts/report-bundle-size/report-as-a-pr-comment.js
deleted file mode 100644
index 062f0a4968..0000000000
--- a/scripts/report-bundle-size/report-as-a-pr-comment.js
+++ /dev/null
@@ -1,181 +0,0 @@
-const { command } = require('../lib/command')
-const { fetchHandlingError } = require('../lib/execution-utils')
-const { getOrg2ApiKey, getGithubAccessToken, getOrg2AppKey } = require('../lib/secrets')
-
-const PR_COMMENT_HEADER = 'Bundles Sizes Evolution'
-const BASE_BRANCH = process.env.MAIN_BRANCH
-const LOCAL_BRANCH = process.env.CI_COMMIT_REF_NAME
-const PR_COMMENTER_AUTH_TOKEN = command`authanywhere`.run().split(' ')[2].trim()
-const GITHUB_TOKEN = getGithubAccessToken()
-const ONE_DAY_IN_SECOND = 24 * 60 * 60
-// The value is set to 5% as it's around 10 times the average value for small PRs.
-const SIZE_INCREASE_THRESHOLD = 5
-
-async function reportBundleSizesAsPrComment(localBundleSizes) {
- const lastCommonCommit = getLastCommonCommit(BASE_BRANCH, LOCAL_BRANCH)
- const pr = await fetchPR(LOCAL_BRANCH)
- if (!pr) {
- console.log('No pull requests found for the branch')
- return
- }
- const packageNames = Object.keys(localBundleSizes)
- const mainBranchBundleSizes = await fetchAllPackagesBaseBundleSize(packageNames, lastCommonCommit)
- const difference = compare(mainBranchBundleSizes, localBundleSizes)
- const commentId = await retrieveExistingCommentId(pr.number)
- await updateOrAddComment(difference, mainBranchBundleSizes, localBundleSizes, pr.number, commentId)
-}
-
-function getLastCommonCommit(baseBranch) {
- try {
- command`git fetch --depth=100 origin ${baseBranch}`.run()
- const commandOutput = command`git merge-base origin/${baseBranch} HEAD`.run()
- // SHA commit is truncated to 8 characters as bundle sizes commit are exported in short format to logs for convenience and readability.
- return commandOutput.trim().substring(0, 8)
- } catch (error) {
- throw new Error('Failed to get last common commit', { cause: error })
- }
-}
-
-async function fetchPR(localBranch) {
- const response = await fetchHandlingError(
- `https://api.github.com/repos/DataDog/browser-sdk/pulls?head=DataDog:${localBranch}`,
- {
- method: 'GET',
- headers: {
- Authorization: `token ${GITHUB_TOKEN}`,
- },
- }
- )
- const pr = response.body ? await response.json() : null
- if (pr && pr.length > 1) {
- throw new Error('Multiple pull requests found for the branch')
- }
- return pr ? pr[0] : null
-}
-
-function fetchAllPackagesBaseBundleSize(packageNames, commitSha) {
- return Promise.all(packageNames.map((packageName) => fetchBundleSizesMetric(packageName, commitSha)))
-}
-
-async function fetchBundleSizesMetric(packageName, commitSha) {
- const now = Math.floor(Date.now() / 1000)
- const date = now - 30 * ONE_DAY_IN_SECOND
- const query = `avg:bundle_sizes.${packageName}{commit:${commitSha}}&from=${date}&to=${now}`
-
- const response = await fetchHandlingError(`https://api.datadoghq.com/api/v1/query?query=${query}`, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- 'DD-API-KEY': getOrg2ApiKey(),
- 'DD-APPLICATION-KEY': getOrg2AppKey(),
- },
- })
- const data = await response.json()
- if (data.series && data.series.length > 0 && data.series[0].pointlist && data.series[0].pointlist.length > 0) {
- return {
- name: packageName,
- size: data.series[0].pointlist[0][1],
- }
- }
- return {
- name: packageName,
- size: null,
- }
-}
-
-function compare(resultsBaseQuery, localBundleSizes) {
- return resultsBaseQuery.map((baseResult) => {
- const localSize = localBundleSizes[baseResult.name]
- let change = null
- let percentageChange = null
-
- if (baseResult.size && localSize) {
- change = localSize - baseResult.size
- percentageChange = ((change / baseResult.size) * 100).toFixed(2)
- }
-
- return {
- name: baseResult.name,
- change,
- percentageChange,
- }
- })
-}
-
-async function retrieveExistingCommentId(prNumber) {
- const response = await fetchHandlingError(
- `https://api.github.com/repos/DataDog/browser-sdk/issues/${prNumber}/comments`,
- {
- method: 'GET',
- headers: {
- Authorization: `token ${GITHUB_TOKEN}`,
- },
- }
- )
- const comments = await response.json()
- const targetComment = comments.find((comment) => comment.body.startsWith(`## ${PR_COMMENT_HEADER}`))
- if (targetComment !== undefined) {
- return targetComment.id
- }
-}
-async function updateOrAddComment(difference, resultsBaseQuery, localBundleSizes, prNumber, commentId) {
- const message = createMessage(difference, resultsBaseQuery, localBundleSizes)
- const method = commentId ? 'PATCH' : 'POST'
- const payload = {
- pr_url: `https://github.com/DataDog/browser-sdk/pull/${prNumber}`,
- message,
- header: PR_COMMENT_HEADER,
- org: 'DataDog',
- repo: 'browser-sdk',
- }
- await fetchHandlingError('https://pr-commenter.us1.ddbuild.io/internal/cit/pr-comment', {
- method,
- headers: {
- Authorization: `Bearer ${PR_COMMENTER_AUTH_TOKEN}`,
- },
- body: JSON.stringify(payload),
- })
-}
-
-function createMessage(difference, resultsBaseQuery, localBundleSizes) {
- let message =
- '| š¦ Bundle Name| Base Size | Local Size | š« | š«% | Status |\n| --- | --- | --- | --- | --- | :---: |\n'
- let highIncreaseDetected = false
- difference.forEach((diff, index) => {
- const baseSize = formatSize(resultsBaseQuery[index].size)
- const localSize = formatSize(localBundleSizes[diff.name])
- const diffSize = formatSize(diff.change)
- const sign = diff.percentageChange > 0 ? '+' : ''
- let status = 'ā
'
- if (diff.percentageChange > SIZE_INCREASE_THRESHOLD) {
- status = 'ā ļø'
- highIncreaseDetected = true
- }
- message += `| ${formatBundleName(diff.name)} | ${baseSize} | ${localSize} | ${diffSize} | ${sign}${diff.percentageChange}% | ${status} |\n`
- })
-
- if (highIncreaseDetected) {
- message += `\nā ļø The increase is particularly high and exceeds ${SIZE_INCREASE_THRESHOLD}%. Please check the changes.`
- }
-
- return message
-}
-
-function formatBundleName(bundleName) {
- return bundleName
- .split('_')
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
- .join(' ')
-}
-
-function formatSize(bytes) {
- if (bytes < 1024) {
- return `${bytes} B`
- }
-
- return `${(bytes / 1024).toFixed(2)} KiB`
-}
-
-module.exports = {
- reportBundleSizesAsPrComment,
-}
diff --git a/test/e2e/scenario/recorder/shadowDom.scenario.ts b/test/e2e/scenario/recorder/shadowDom.scenario.ts
index 8318727383..3d56264ddd 100644
--- a/test/e2e/scenario/recorder/shadowDom.scenario.ts
+++ b/test/e2e/scenario/recorder/shadowDom.scenario.ts
@@ -1,11 +1,17 @@
-import type { DocumentFragmentNode, MouseInteractionData, SerializedNodeWithId } from '@datadog/browser-rum/src/types'
-import { MouseInteractionType, NodeType } from '@datadog/browser-rum/src/types'
+import type {
+ DocumentFragmentNode,
+ MouseInteractionData,
+ ScrollData,
+ SerializedNodeWithId,
+} from '@datadog/browser-rum/src/types'
+import { IncrementalSource, MouseInteractionType, NodeType } from '@datadog/browser-rum/src/types'
import {
createMutationPayloadValidatorFromSegment,
findElementWithIdAttribute,
findElementWithTagName,
findFullSnapshot,
+ findIncrementalSnapshot,
findMouseInteractionRecords,
findNode,
findTextContent,
@@ -80,6 +86,49 @@ const divShadowDom = `
`
+/** Will generate the following HTML
+ * ```html
+ *
+ * #shadow-root
+ *
+ *
+ *
+ *```
+ when called like ``
+ */
+const scrollableDivShadowDom = `
+ `
+
/** Will generate the following HTML
* ```html
*
@@ -244,6 +293,31 @@ describe('recorder with shadow DOM', () => {
],
})
})
+
+ createTest('can record scroll from inside the shadow root')
+ .withRum({})
+ .withSetup(bundleSetup)
+ .withBody(html`
+ ${scrollableDivShadowDom}
+
+ `)
+ .run(async ({ intakeRegistry }) => {
+ const button = await getNodeInsideShadowDom('my-scrollable-div', 'button')
+
+ // Triggering scrollTo from the test itself is not allowed
+ // Thus, a callback to scroll the div was added to the button 'click' event
+ await button.click()
+
+ await flushEvents()
+ expect(intakeRegistry.replaySegments.length).toBe(1)
+ const scrollRecord = findIncrementalSnapshot(intakeRegistry.replaySegments[0], IncrementalSource.Scroll)
+ const fullSnapshot = findFullSnapshot(intakeRegistry.replaySegments[0])!
+ const divNode = findElementWithIdAttribute(fullSnapshot.data.node, 'scrollable-div')!
+
+ expect(scrollRecord).toBeTruthy()
+ expect((scrollRecord?.data as ScrollData).id).toBe(divNode.id)
+ expect((scrollRecord?.data as ScrollData).y).toBe(250)
+ })
})
function findElementsInShadowDom(node: SerializedNodeWithId, id: string) {
diff --git a/yarn.lock b/yarn.lock
index 0fcf7c016d..acc459371e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -372,20 +372,20 @@ __metadata:
"@datadog/browser-core": "workspace:*"
"@datadog/browser-logs": "workspace:*"
"@datadog/browser-rum": "workspace:*"
- "@mantine/core": 7.7.1
- "@mantine/hooks": 7.7.1
- "@tabler/icons-react": 3.1.0
+ "@mantine/core": 7.8.0
+ "@mantine/hooks": 7.8.0
+ "@tabler/icons-react": 3.2.0
"@types/chrome": 0.0.266
- "@types/react": 18.2.74
- "@types/react-dom": 18.2.24
+ "@types/react": 18.2.79
+ "@types/react-dom": 18.2.25
"@webextension-toolbox/webpack-webextension-plugin": 3.3.1
clsx: 2.1.0
copy-webpack-plugin: 12.0.2
- css-loader: 7.1.0
+ css-loader: 6.11.0
html-webpack-plugin: 5.6.0
react: 18.2.0
react-dom: 18.2.0
- style-loader: 3.3.4
+ style-loader: 4.0.0
webpack: 5.91.0
languageName: unknown
linkType: soft
@@ -428,10 +428,10 @@ __metadata:
languageName: node
linkType: hard
-"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1":
- version: 4.8.0
- resolution: "@eslint-community/regexpp@npm:4.8.0"
- checksum: 601e6d033d556e98e8c929905bef335f20d7389762812df4d0f709d9b4d2631610dda975fb272e23b5b68e24a163b3851b114c8080a0a19fb4c141a1eff6305b
+"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1":
+ version: 4.10.0
+ resolution: "@eslint-community/regexpp@npm:4.10.0"
+ checksum: 2a6e345429ea8382aaaf3a61f865cae16ed44d31ca917910033c02dc00d505d939f10b81e079fa14d43b51499c640138e153b7e40743c4c094d9df97d4e56f7b
languageName: node
linkType: hard
@@ -766,9 +766,9 @@ __metadata:
languageName: node
linkType: hard
-"@mantine/core@npm:7.7.1":
- version: 7.7.1
- resolution: "@mantine/core@npm:7.7.1"
+"@mantine/core@npm:7.8.0":
+ version: 7.8.0
+ resolution: "@mantine/core@npm:7.8.0"
dependencies:
"@floating-ui/react": ^0.26.9
clsx: 2.1.0
@@ -777,19 +777,19 @@ __metadata:
react-textarea-autosize: 8.5.3
type-fest: ^4.12.0
peerDependencies:
- "@mantine/hooks": 7.7.1
+ "@mantine/hooks": 7.8.0
react: ^18.2.0
react-dom: ^18.2.0
- checksum: d3860a2ab7bbe02a32c0afb94f7fbe24b6c3cf24803a594b3aed492bb6730756758068cad049ac8a25a9641e48b986d4ef71e8bd517441985cf41f29960d4fce
+ checksum: 17dc89759e24881d9939d0a6225edc62cd6bfb8fb99a06499d4103c500246f79b87b1465765fd7edc9d38399c6880ee57e4a747faf9e42da1577ec94b7fe3f47
languageName: node
linkType: hard
-"@mantine/hooks@npm:7.7.1":
- version: 7.7.1
- resolution: "@mantine/hooks@npm:7.7.1"
+"@mantine/hooks@npm:7.8.0":
+ version: 7.8.0
+ resolution: "@mantine/hooks@npm:7.8.0"
peerDependencies:
react: ^18.2.0
- checksum: 7f9e6f32783aa051ad9eef14353a1202c501fc23e7ec1f85dbaf7c497b996d9b00e8042dc25bc7929940e7111da3c9f2421ef0dc98a6e11c9babfe69b1aeb6ea
+ checksum: e8041d55e4f56731c210d386051b93a242350d8e79c8a61b642d761e432e393cc1067901335d9e9fdb70d21e326584ee291afde5c4e1a332a4dad937f8da07d5
languageName: node
linkType: hard
@@ -1261,9 +1261,9 @@ __metadata:
languageName: node
linkType: hard
-"@puppeteer/browsers@npm:2.2.1":
- version: 2.2.1
- resolution: "@puppeteer/browsers@npm:2.2.1"
+"@puppeteer/browsers@npm:2.2.2":
+ version: 2.2.2
+ resolution: "@puppeteer/browsers@npm:2.2.2"
dependencies:
debug: 4.3.4
extract-zip: 2.0.1
@@ -1275,7 +1275,7 @@ __metadata:
yargs: 17.7.2
bin:
browsers: lib/cjs/main-cli.js
- checksum: c2ec8bac9978ae6279d67442a3a81c517db1e172bd4603d1983eb48de12b088d8b565b1817abe21ba6df76be9a68e3fc543d4c7111c964a93f3ac9b14f7c76e5
+ checksum: 328a10ceb432784ec4cd524c461799936603b8436e50eed6a61127022f4c8a36ba31143b0d4d311190d619968f2e9db9fa7ac046757cff2c9f81d301110560be
languageName: node
linkType: hard
@@ -1377,21 +1377,21 @@ __metadata:
languageName: node
linkType: hard
-"@tabler/icons-react@npm:3.1.0":
- version: 3.1.0
- resolution: "@tabler/icons-react@npm:3.1.0"
+"@tabler/icons-react@npm:3.2.0":
+ version: 3.2.0
+ resolution: "@tabler/icons-react@npm:3.2.0"
dependencies:
- "@tabler/icons": 3.1.0
+ "@tabler/icons": 3.2.0
peerDependencies:
react: ">= 16"
- checksum: 8f82ea699f548450801d8b7bbe1252850304a425b79c62807118432af907b8239ce7a4524dc28f81278d947ea0b2b32f3f7a4601f4c1e5585ba5446326b354ec
+ checksum: 4412ecc1f3a3a2a4b85f122365ccfa7fabb1c84a7e40a6f2f31f155e12cf43b5772f84a079281b50d61f3dc916e8ff2c26f14b07c36b082f9937695220bb79cb
languageName: node
linkType: hard
-"@tabler/icons@npm:3.1.0":
- version: 3.1.0
- resolution: "@tabler/icons@npm:3.1.0"
- checksum: 3dd9c54ec46dbf12571cc8a72e10f99f1b84e99eeb53170254e1ab0939b3d37b9c8031a5e6534315b7d3107e0724f7fae61749f9c159ac8fd34cf8d3b9f5e6cc
+"@tabler/icons@npm:3.2.0":
+ version: 3.2.0
+ resolution: "@tabler/icons@npm:3.2.0"
+ checksum: 61085d3c268269445ac5df7174aed6837e968b14d18255d057c86301226472cbd55912767cbb154ce6afd4482293d2237f5c1b80348b29e02c45535dd8b87352
languageName: node
linkType: hard
@@ -1690,10 +1690,10 @@ __metadata:
languageName: node
linkType: hard
-"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.11, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9":
- version: 7.0.12
- resolution: "@types/json-schema@npm:7.0.12"
- checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293
+"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.11, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9":
+ version: 7.0.15
+ resolution: "@types/json-schema@npm:7.0.15"
+ checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98
languageName: node
linkType: hard
@@ -1755,12 +1755,12 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:*, @types/node@npm:20.12.5, @types/node@npm:>=10.0.0, @types/node@npm:^20.1.0, @types/node@npm:^20.1.1, @types/node@npm:^20.11.28":
- version: 20.12.5
- resolution: "@types/node@npm:20.12.5"
+"@types/node@npm:*, @types/node@npm:20.12.7, @types/node@npm:>=10.0.0, @types/node@npm:^20.1.0, @types/node@npm:^20.1.1, @types/node@npm:^20.11.28":
+ version: 20.12.7
+ resolution: "@types/node@npm:20.12.7"
dependencies:
undici-types: ~5.26.4
- checksum: 38358c091392bb3def1136772ada4ccd39a9429d459160b5ab728b690d2f15f2212eafd9e65ce716e270f70a4e6927ebffccfefc08dabdf68f4016c1fc8a7938
+ checksum: 7cc979f7e2ca9a339ec71318c3901b9978555257929ef3666987f3e447123bc6dc92afcc89f6347e09e07d602fde7d51bcddea626c23aa2bb74aeaacfd1e1686
languageName: node
linkType: hard
@@ -1806,29 +1806,29 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-dom@npm:18.2.24":
- version: 18.2.24
- resolution: "@types/react-dom@npm:18.2.24"
+"@types/react-dom@npm:18.2.25":
+ version: 18.2.25
+ resolution: "@types/react-dom@npm:18.2.25"
dependencies:
"@types/react": "*"
- checksum: 7fb0dd0c88c5219bcc27f1f9bf14d9e1b1593014ee7938dd46ee9782c77c39d1ccc79d2b8364a6113019d7f65c94e4dc3c37425c3972910bb2674cce98d3f3ca
+ checksum: 85f9278d6456c6cdc76da6806a33b472588cdd029b08dde32e8b5636b25a3eae529b4ac2e08c848a3d7ca44e4e97ee9a3df406c96fa0768de935c8eed6e07590
languageName: node
linkType: hard
-"@types/react@npm:*, @types/react@npm:18.2.74":
- version: 18.2.74
- resolution: "@types/react@npm:18.2.74"
+"@types/react@npm:*, @types/react@npm:18.2.79":
+ version: 18.2.79
+ resolution: "@types/react@npm:18.2.79"
dependencies:
"@types/prop-types": "*"
csstype: ^3.0.2
- checksum: 093c0e350552e61393e2ba30169aa620e2e64c1e2d0ff38efd2a7549ded689b6ab6bffb65fe0f7ef9e143174de54442d942bd70c014649f464c52465701208d8
+ checksum: 85aa96e0e88725c84d8fc5f04f10a4da6a1f507dde33557ac9cc211414756867721264bfefd9e02bae1288ce2905351d949b652b931e734ea24519ee5c625138
languageName: node
linkType: hard
-"@types/semver@npm:^7.5.0":
- version: 7.5.1
- resolution: "@types/semver@npm:7.5.1"
- checksum: 2fffe938c7ac168711f245a16e1856a3578d77161ca17e29a05c3e02c7be3e9c5beefa29a3350f6c1bd982fb70aa28cc52e4845eb7d36246bcdc0377170d584d
+"@types/semver@npm:^7.5.8":
+ version: 7.5.8
+ resolution: "@types/semver@npm:7.5.8"
+ checksum: ea6f5276f5b84c55921785a3a27a3cd37afee0111dfe2bcb3e03c31819c197c782598f17f0b150a69d453c9584cd14c4c4d7b9a55d2c5e6cacd4d66fdb3b3663
languageName: node
linkType: hard
@@ -1907,126 +1907,126 @@ __metadata:
languageName: node
linkType: hard
-"@typescript-eslint/eslint-plugin@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/eslint-plugin@npm:7.5.0"
+"@typescript-eslint/eslint-plugin@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/eslint-plugin@npm:7.7.0"
dependencies:
- "@eslint-community/regexpp": ^4.5.1
- "@typescript-eslint/scope-manager": 7.5.0
- "@typescript-eslint/type-utils": 7.5.0
- "@typescript-eslint/utils": 7.5.0
- "@typescript-eslint/visitor-keys": 7.5.0
+ "@eslint-community/regexpp": ^4.10.0
+ "@typescript-eslint/scope-manager": 7.7.0
+ "@typescript-eslint/type-utils": 7.7.0
+ "@typescript-eslint/utils": 7.7.0
+ "@typescript-eslint/visitor-keys": 7.7.0
debug: ^4.3.4
graphemer: ^1.4.0
- ignore: ^5.2.4
+ ignore: ^5.3.1
natural-compare: ^1.4.0
- semver: ^7.5.4
- ts-api-utils: ^1.0.1
+ semver: ^7.6.0
+ ts-api-utils: ^1.3.0
peerDependencies:
"@typescript-eslint/parser": ^7.0.0
eslint: ^8.56.0
peerDependenciesMeta:
typescript:
optional: true
- checksum: 02ca180a4e46df840b84221219800cc5f6371254a37be7932a2586768925d8c8897b9eebe92d32093be254a98f10eae8b291638515edd79571826d6840044332
+ checksum: f97348425d114282407f4f524cdc618199d0d6d86e4e556709063b07611192068872cbd7f612cbd670617d958ee4519b25eeca0bccbac1b08433ce41511d3825
languageName: node
linkType: hard
-"@typescript-eslint/parser@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/parser@npm:7.5.0"
+"@typescript-eslint/parser@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/parser@npm:7.7.0"
dependencies:
- "@typescript-eslint/scope-manager": 7.5.0
- "@typescript-eslint/types": 7.5.0
- "@typescript-eslint/typescript-estree": 7.5.0
- "@typescript-eslint/visitor-keys": 7.5.0
+ "@typescript-eslint/scope-manager": 7.7.0
+ "@typescript-eslint/types": 7.7.0
+ "@typescript-eslint/typescript-estree": 7.7.0
+ "@typescript-eslint/visitor-keys": 7.7.0
debug: ^4.3.4
peerDependencies:
eslint: ^8.56.0
peerDependenciesMeta:
typescript:
optional: true
- checksum: c9f85ae638e27fb249e565fc299cfee456b15f6a67156f373c10fa6e310a470b5298e174ca75309789c4cf1acd1a9fd3391d5fe128208b05bac0b701d5ddf512
+ checksum: 44dc88eae2fafd3ae92338683d70d077d0c4342dcd4949dc05ffa7686de2753b8565c643eedb3bf1c6b6c1b4a2f0849000474b8e70572184ebe366b0b1dbb1ee
languageName: node
linkType: hard
-"@typescript-eslint/scope-manager@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/scope-manager@npm:7.5.0"
+"@typescript-eslint/scope-manager@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/scope-manager@npm:7.7.0"
dependencies:
- "@typescript-eslint/types": 7.5.0
- "@typescript-eslint/visitor-keys": 7.5.0
- checksum: 13d858ca9f77922578b154b8568ca172dc8bd3a557ec60b4d027174675e243e34f189127ae073b052c78a96aca2cbad098318388db8723bce25d0a63dd0ba8e3
+ "@typescript-eslint/types": 7.7.0
+ "@typescript-eslint/visitor-keys": 7.7.0
+ checksum: cb280d4aa64cdefee362ef97b6fde3ae86a376fccff7f012e4e635ffe544dd90be37b340c7099784d0fbebb37b925aab6b53195825b41cee38e2382d0b552871
languageName: node
linkType: hard
-"@typescript-eslint/type-utils@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/type-utils@npm:7.5.0"
+"@typescript-eslint/type-utils@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/type-utils@npm:7.7.0"
dependencies:
- "@typescript-eslint/typescript-estree": 7.5.0
- "@typescript-eslint/utils": 7.5.0
+ "@typescript-eslint/typescript-estree": 7.7.0
+ "@typescript-eslint/utils": 7.7.0
debug: ^4.3.4
- ts-api-utils: ^1.0.1
+ ts-api-utils: ^1.3.0
peerDependencies:
eslint: ^8.56.0
peerDependenciesMeta:
typescript:
optional: true
- checksum: 9dce5f7f9981febd5967c3c45266787ddf5805fcef40fd2cb644503a32aee4d06de77d64dc3903e61caff3a1a76817c0b3be35703401ddf1bec84c76757f0f69
+ checksum: 74c07e4fcc8e6ee7870a161596d25ecfa22624947d94ca9af7147590caa13b6388f0e55101961ab02f77e7e6cffdaf19895575d7329dda50fa18fc71bf15f6b7
languageName: node
linkType: hard
-"@typescript-eslint/types@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/types@npm:7.5.0"
- checksum: 038e5b10680fd32da8455d0590437888f57511ed8c2b984511890d6bfc0b230b269bc3de6970cc76660e8fd65657e201316bc4abd9758a2d6efb49d659dd4199
+"@typescript-eslint/types@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/types@npm:7.7.0"
+ checksum: c47aae2c1474b85fab012e0518c57685c595f11775b615b6a6749f943aa7a98554d9eb7054114850679f46699578049998408a492e0c1abd3bded2aee8e261a5
languageName: node
linkType: hard
-"@typescript-eslint/typescript-estree@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/typescript-estree@npm:7.5.0"
+"@typescript-eslint/typescript-estree@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/typescript-estree@npm:7.7.0"
dependencies:
- "@typescript-eslint/types": 7.5.0
- "@typescript-eslint/visitor-keys": 7.5.0
+ "@typescript-eslint/types": 7.7.0
+ "@typescript-eslint/visitor-keys": 7.7.0
debug: ^4.3.4
globby: ^11.1.0
is-glob: ^4.0.3
- minimatch: 9.0.3
- semver: ^7.5.4
- ts-api-utils: ^1.0.1
+ minimatch: ^9.0.4
+ semver: ^7.6.0
+ ts-api-utils: ^1.3.0
peerDependenciesMeta:
typescript:
optional: true
- checksum: ebc6838af9cf25be3c07ba4ea91bbbc2450d835eeb775139a0ed6344baf193824b0fd5319c0fe94d55c822a54670344655937894f6d0dc77bfbfcdc0493e567d
+ checksum: 54d16b2a083bff3c6d38fbee56465403bbcba411bf25e94f2d8bbbbd8b4b35c151c7845997e5141224f8dba5bc1f34964762713035d49113700efd7381246d02
languageName: node
linkType: hard
-"@typescript-eslint/utils@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/utils@npm:7.5.0"
+"@typescript-eslint/utils@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/utils@npm:7.7.0"
dependencies:
"@eslint-community/eslint-utils": ^4.4.0
- "@types/json-schema": ^7.0.12
- "@types/semver": ^7.5.0
- "@typescript-eslint/scope-manager": 7.5.0
- "@typescript-eslint/types": 7.5.0
- "@typescript-eslint/typescript-estree": 7.5.0
- semver: ^7.5.4
+ "@types/json-schema": ^7.0.15
+ "@types/semver": ^7.5.8
+ "@typescript-eslint/scope-manager": 7.7.0
+ "@typescript-eslint/types": 7.7.0
+ "@typescript-eslint/typescript-estree": 7.7.0
+ semver: ^7.6.0
peerDependencies:
eslint: ^8.56.0
- checksum: 03d5563f50da5f35c84c7ea9dd1c671afa668d614eacb3dff38a94b9f399bd4e371348f6a2feb1cbf0fcb3e3e6d0f662cef8d93a9f3a29ea9a4176aa3abc4902
+ checksum: 830ff3af96538083d7513c211e39f07375b7e973c135a2b9bbae1ad7509bd4dce33a144a22d896a2ff4c18e9fcccd423535b6f9bb8adafe36e800f16bc53378c
languageName: node
linkType: hard
-"@typescript-eslint/visitor-keys@npm:7.5.0":
- version: 7.5.0
- resolution: "@typescript-eslint/visitor-keys@npm:7.5.0"
+"@typescript-eslint/visitor-keys@npm:7.7.0":
+ version: 7.7.0
+ resolution: "@typescript-eslint/visitor-keys@npm:7.7.0"
dependencies:
- "@typescript-eslint/types": 7.5.0
- eslint-visitor-keys: ^3.4.1
- checksum: 8de0d3fb470f60b3aca7073ff62c7f9fe078d77c48d43033622ff059f201223fe35eaf834a6b63d95ee5d4c0e2e13669de3f20e4f4de597596dcf63537a60693
+ "@typescript-eslint/types": 7.7.0
+ eslint-visitor-keys: ^3.4.3
+ checksum: 16d0b63b9d98ea1d3d20bd6f9dc3cbd2674055845ad493d98118669d54792b1c167f57ae25beaae2c1107ed07012ac3c3093cca978b2ab49833dc491bc302b33
languageName: node
linkType: hard
@@ -2048,16 +2048,16 @@ __metadata:
languageName: node
linkType: hard
-"@wdio/browserstack-service@npm:8.35.1":
- version: 8.35.1
- resolution: "@wdio/browserstack-service@npm:8.35.1"
+"@wdio/browserstack-service@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/browserstack-service@npm:8.36.0"
dependencies:
"@percy/appium-app": ^2.0.1
"@percy/selenium-webdriver": ^2.0.3
"@types/gitconfiglocal": ^2.0.1
"@wdio/logger": 8.28.0
- "@wdio/reporter": 8.32.4
- "@wdio/types": 8.32.4
+ "@wdio/reporter": 8.36.0
+ "@wdio/types": 8.36.0
browserstack-local: ^1.5.1
chalk: ^5.3.0
csv-writer: ^1.6.0
@@ -2066,27 +2066,27 @@ __metadata:
gitconfiglocal: ^2.1.0
got: ^12.6.1
uuid: ^9.0.0
- webdriverio: 8.35.1
+ webdriverio: 8.36.0
winston-transport: ^4.5.0
yauzl: ^3.0.0
peerDependencies:
"@wdio/cli": ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
- checksum: 76c3b6bf58d79be36e0f1b5f0db8465c9c5c355cdb9a3a275088c587730ad3fa410a60a9fcc5382dd4e0fa71dba8a2101783ea1dc7568f84b197bcad6aafbf41
+ checksum: 38718cb71794f4e22a214b6f345d38c42e6a03b87155487e01860051158f91209eb9f2e286bbfd620f4716600910b2e8da3dafb5b55429451dd327458a7e59c0
languageName: node
linkType: hard
-"@wdio/cli@npm:8.35.1":
- version: 8.35.1
- resolution: "@wdio/cli@npm:8.35.1"
+"@wdio/cli@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/cli@npm:8.36.0"
dependencies:
"@types/node": ^20.1.1
"@vitest/snapshot": ^1.2.1
- "@wdio/config": 8.35.0
- "@wdio/globals": 8.35.1
+ "@wdio/config": 8.36.0
+ "@wdio/globals": 8.36.0
"@wdio/logger": 8.28.0
"@wdio/protocols": 8.32.0
- "@wdio/types": 8.32.4
- "@wdio/utils": 8.35.0
+ "@wdio/types": 8.36.0
+ "@wdio/utils": 8.36.0
async-exit-hook: ^2.0.1
chalk: ^5.2.0
chokidar: ^3.5.3
@@ -2101,84 +2101,84 @@ __metadata:
lodash.union: ^4.6.0
read-pkg-up: 10.0.0
recursive-readdir: ^2.2.3
- webdriverio: 8.35.1
+ webdriverio: 8.36.0
yargs: ^17.7.2
bin:
wdio: bin/wdio.js
- checksum: 4371cff010e53ce74919a955c7d6635b6ff109151ba24611698c8bd10d1301374d15c7849b827917c5e3855aab1f9b58b3075af826c4869636338684ecfaf7b0
+ checksum: 4899ff1ddf0df7ecc2b521b1c74809a9dd6a6641d3e88dfa7429fe6143b95f77000753cc969e6a59b2f1070681123a56633af588c91fb76232a43bc45fafe0df
languageName: node
linkType: hard
-"@wdio/config@npm:8.35.0":
- version: 8.35.0
- resolution: "@wdio/config@npm:8.35.0"
+"@wdio/config@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/config@npm:8.36.0"
dependencies:
"@wdio/logger": 8.28.0
- "@wdio/types": 8.32.4
- "@wdio/utils": 8.35.0
+ "@wdio/types": 8.36.0
+ "@wdio/utils": 8.36.0
decamelize: ^6.0.0
deepmerge-ts: ^5.0.0
glob: ^10.2.2
import-meta-resolve: ^4.0.0
- checksum: 90df0ba14a48164b150e5e096ef3d6759cadeb64c6ffdce12b25763156eea7bf0da55cc7e3f44ea4e69030c0189116ee7662ab97a2de67615143afd32e7bfb01
+ checksum: a96a26c0bb309b42c915f9568493e478a351937d9eec985301b0353f0da4d94a16086ec97f0d4caa08dc6b61be0513024897d28fe90783ea36c9a130cfab3db1
languageName: node
linkType: hard
-"@wdio/globals@npm:8.35.1, @wdio/globals@npm:^8.29.3":
- version: 8.35.1
- resolution: "@wdio/globals@npm:8.35.1"
+"@wdio/globals@npm:8.36.0, @wdio/globals@npm:^8.29.3":
+ version: 8.36.0
+ resolution: "@wdio/globals@npm:8.36.0"
dependencies:
expect-webdriverio: ^4.11.2
- webdriverio: 8.35.1
+ webdriverio: 8.36.0
dependenciesMeta:
expect-webdriverio:
optional: true
webdriverio:
optional: true
- checksum: 6f46ca6e34251baf6794a0cd9739c119185a0de351785e135a5567fe1eec21281d26f09079df71a963c55ff687182685e18336cb5549914fb554ec95b8b99175
+ checksum: f57ded6f8b945abcac1fffe77d30f71e85ea9321899f660ce492aa27825cd6814fda2b3b30c993a0a1c2cfb94ba5158ac0a8dd89a50e768fcc5ceefc851bf282
languageName: node
linkType: hard
-"@wdio/jasmine-framework@npm:8.35.1":
- version: 8.35.1
- resolution: "@wdio/jasmine-framework@npm:8.35.1"
+"@wdio/jasmine-framework@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/jasmine-framework@npm:8.36.0"
dependencies:
"@types/node": ^20.1.0
- "@wdio/globals": 8.35.1
+ "@wdio/globals": 8.36.0
"@wdio/logger": 8.28.0
- "@wdio/types": 8.32.4
- "@wdio/utils": 8.35.0
+ "@wdio/types": 8.36.0
+ "@wdio/utils": 8.36.0
expect-webdriverio: ^4.11.2
jasmine: ^5.0.0
- checksum: 0ed8f60c0c591c916051a470afc65fb3e6ee7d0cd19b30805f5eee42e7027a3646f593b48659e086fefd3be35fc7ec25eb1a02475ca5a7d934773ec5578b7db1
+ checksum: 08f60071c8dedff04d631d70cdd65ece063843ae0979ce61ed747aa1b99672c43ab3bd93ebf8c5283d6065ed92743baae8016836fe817956a57dac104f0fc31c
languageName: node
linkType: hard
-"@wdio/junit-reporter@npm:8.32.4":
- version: 8.32.4
- resolution: "@wdio/junit-reporter@npm:8.32.4"
+"@wdio/junit-reporter@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/junit-reporter@npm:8.36.0"
dependencies:
- "@wdio/reporter": 8.32.4
- "@wdio/types": 8.32.4
+ "@wdio/reporter": 8.36.0
+ "@wdio/types": 8.36.0
json-stringify-safe: ^5.0.1
junit-report-builder: ^3.0.0
- checksum: 8e13e0597025e7d2d461c9c5f983ec195d6b29e355b370bf3a0d69ab352eba3aa9080e35a50a47d34d8b34aa9ed0ce5a8e32dad19c03df846da69898a475e1e7
+ checksum: 5e4c9fdb1c4d347bd0ff3056e58ef829ae61f34464fd93856d82247e0d07c523d14db008b03734fce547a157398c2dbe56676657bc526b811cd7955f3b28984e
languageName: node
linkType: hard
-"@wdio/local-runner@npm:8.35.1":
- version: 8.35.1
- resolution: "@wdio/local-runner@npm:8.35.1"
+"@wdio/local-runner@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/local-runner@npm:8.36.0"
dependencies:
"@types/node": ^20.1.0
"@wdio/logger": 8.28.0
"@wdio/repl": 8.24.12
- "@wdio/runner": 8.35.1
- "@wdio/types": 8.32.4
+ "@wdio/runner": 8.36.0
+ "@wdio/types": 8.36.0
async-exit-hook: ^2.0.1
split2: ^4.1.0
stream-buffers: ^3.0.2
- checksum: 2cca8ce9b6cfee44479cc49c09e394f6efd855d44fa4f856ea1c1b472270c0a6a32380165442fb8c807c2d16e93f26b94f45a8b30a71769a999c996d60b86e93
+ checksum: 7d5d669762c659cc1e36d3c1adcdaf446bdbdb2a12b350ef0060c22b563bc5f829354066a175f95f2496215b6a9d5d9d2c13fffebbfed251a532fcdce139977b
languageName: node
linkType: hard
@@ -2210,67 +2210,67 @@ __metadata:
languageName: node
linkType: hard
-"@wdio/reporter@npm:8.32.4":
- version: 8.32.4
- resolution: "@wdio/reporter@npm:8.32.4"
+"@wdio/reporter@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/reporter@npm:8.36.0"
dependencies:
"@types/node": ^20.1.0
"@wdio/logger": 8.28.0
- "@wdio/types": 8.32.4
+ "@wdio/types": 8.36.0
diff: ^5.0.0
object-inspect: ^1.12.0
- checksum: 4fd3a615ec658e1059f3104bc9b2b6c38fbe513fab8f5bc47045602fe919b1c955cec00a9f9e1d828d3e297c565a1f44437d4f6705bd2644a91bffbe6e211465
+ checksum: 27b520ee30b1c38a744d9df6c5e4837d05ccf147dec0d07bca4ff289bbdc61caf9fe739b7f278adaf4325c00957b7175c4b36e971ed7a64be360271740885f8d
languageName: node
linkType: hard
-"@wdio/runner@npm:8.35.1":
- version: 8.35.1
- resolution: "@wdio/runner@npm:8.35.1"
+"@wdio/runner@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/runner@npm:8.36.0"
dependencies:
"@types/node": ^20.11.28
- "@wdio/config": 8.35.0
- "@wdio/globals": 8.35.1
+ "@wdio/config": 8.36.0
+ "@wdio/globals": 8.36.0
"@wdio/logger": 8.28.0
- "@wdio/types": 8.32.4
- "@wdio/utils": 8.35.0
+ "@wdio/types": 8.36.0
+ "@wdio/utils": 8.36.0
deepmerge-ts: ^5.1.0
expect-webdriverio: ^4.12.0
gaze: ^1.1.3
- webdriver: 8.35.0
- webdriverio: 8.35.1
- checksum: 5c860caa0b6b08b40a569591a53f8afc7776b8dec89f8759006667696de1aba8bb9c29b54ec1fdd237cd57d57d6918e3d707169ce9364c4162956d40007638b4
+ webdriver: 8.36.0
+ webdriverio: 8.36.0
+ checksum: e0faa34e8e8df75b806cf3271722bc62c002816ba03cac289e998a7518f1fcbbc4446871420bc395c47ba6a39a01d8d68d97ed999031598b7644832b9413d2f4
languageName: node
linkType: hard
-"@wdio/spec-reporter@npm:8.32.4":
- version: 8.32.4
- resolution: "@wdio/spec-reporter@npm:8.32.4"
+"@wdio/spec-reporter@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/spec-reporter@npm:8.36.0"
dependencies:
- "@wdio/reporter": 8.32.4
- "@wdio/types": 8.32.4
+ "@wdio/reporter": 8.36.0
+ "@wdio/types": 8.36.0
chalk: ^5.1.2
easy-table: ^1.2.0
pretty-ms: ^7.0.0
- checksum: d4d28f86de9665306447d1fc2d08e1695200a80de2d8e60d98b4636010923b8e614fdf83a91df128fc1abadfad404a1f8e3c30ddbd2b5f232c78caac5008b300
+ checksum: 006aae9d25c374487e557a78cc6fa99adaf4d6e372f71ae0817603a09a513b292247d28ca7b39126dfb1a2b5cf1bfcd7d1b597e2f990c8e44e33747a19730d76
languageName: node
linkType: hard
-"@wdio/types@npm:8.32.4":
- version: 8.32.4
- resolution: "@wdio/types@npm:8.32.4"
+"@wdio/types@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/types@npm:8.36.0"
dependencies:
"@types/node": ^20.1.0
- checksum: c7f051f3e48dffb3f3963d71dcf16fa600b53333cf5ef66a501211e6f747389a6763b311dba6f81d60e8819498604dd4fbc341f5745e9a5a20e727ec746bb8d9
+ checksum: cfaf9f9e188bb2bda4140e95615f3ae33dd894b82a2a11966215a6b58ce8e9a575d4356e9efe77a9982c26401b8987f60eb2def3bc9c505fbf1b4c6c3cdf546b
languageName: node
linkType: hard
-"@wdio/utils@npm:8.35.0":
- version: 8.35.0
- resolution: "@wdio/utils@npm:8.35.0"
+"@wdio/utils@npm:8.36.0":
+ version: 8.36.0
+ resolution: "@wdio/utils@npm:8.36.0"
dependencies:
"@puppeteer/browsers": ^1.6.0
"@wdio/logger": 8.28.0
- "@wdio/types": 8.32.4
+ "@wdio/types": 8.36.0
decamelize: ^6.0.0
deepmerge-ts: ^5.1.0
edgedriver: ^5.3.5
@@ -2281,7 +2281,7 @@ __metadata:
safaridriver: ^0.1.0
split2: ^4.2.0
wait-port: ^1.0.4
- checksum: 14c379b8ef80fce0909404756d015a06d7e3887088023f0ca53288c5370692be13b643a45aa60b66c427c8a5b789afbc8f9333a67a6a81a9b612d0858928e9bd
+ checksum: 25b5bdf226e9ad4077da72ccb0d05b6cc75e02000a8575221d22486875ee7eeb27565ecf7cdd5dd59b63c5614c80fe6bd46a9dc29107bd14590d68109c8ac18e
languageName: node
linkType: hard
@@ -3236,14 +3236,14 @@ __metadata:
"@types/cors": 2.8.17
"@types/express": 4.17.21
"@types/jasmine": 3.10.18
- "@typescript-eslint/eslint-plugin": 7.5.0
- "@typescript-eslint/parser": 7.5.0
- "@wdio/browserstack-service": 8.35.1
- "@wdio/cli": 8.35.1
- "@wdio/jasmine-framework": 8.35.1
- "@wdio/junit-reporter": 8.32.4
- "@wdio/local-runner": 8.35.1
- "@wdio/spec-reporter": 8.32.4
+ "@typescript-eslint/eslint-plugin": 7.7.0
+ "@typescript-eslint/parser": 7.7.0
+ "@wdio/browserstack-service": 8.36.0
+ "@wdio/cli": 8.36.0
+ "@wdio/jasmine-framework": 8.36.0
+ "@wdio/junit-reporter": 8.36.0
+ "@wdio/local-runner": 8.36.0
+ "@wdio/spec-reporter": 8.36.0
ajv: 6.12.6
browserstack-local: 1.5.5
chrome-webstore-upload: 3.0.3
@@ -3280,8 +3280,8 @@ __metadata:
ts-loader: 9.5.1
ts-node: 10.9.2
tsconfig-paths-webpack-plugin: 4.1.0
- typescript: 5.4.4
- webdriverio: 8.35.1
+ typescript: 5.4.5
+ webdriverio: 8.36.0
webpack: 5.91.0
webpack-cli: 5.1.4
webpack-dev-middleware: 7.2.1
@@ -3681,16 +3681,16 @@ __metadata:
languageName: node
linkType: hard
-"chromium-bidi@npm:0.5.16":
- version: 0.5.16
- resolution: "chromium-bidi@npm:0.5.16"
+"chromium-bidi@npm:0.5.17":
+ version: 0.5.17
+ resolution: "chromium-bidi@npm:0.5.17"
dependencies:
mitt: 3.0.1
urlpattern-polyfill: 10.0.0
zod: 3.22.4
peerDependencies:
devtools-protocol: "*"
- checksum: 5206876e240549daadfa390ae6475e8c891a0557006e0dea13590e2f5ed26b560fa9cbf5c654dde0a95a2c13d606e527de745b52c25273b6c200d9cbca4e6522
+ checksum: 522da996ed5abfb47707583cc24785f9aa05d87bd968dbd520f245cf8972fa3ec102f8d1d72fa07558daa70495d8c6f2bf364d8599eb60b77504e528601d8a30
languageName: node
linkType: hard
@@ -4288,9 +4288,9 @@ __metadata:
languageName: node
linkType: hard
-"css-loader@npm:7.1.0":
- version: 7.1.0
- resolution: "css-loader@npm:7.1.0"
+"css-loader@npm:6.11.0":
+ version: 6.11.0
+ resolution: "css-loader@npm:6.11.0"
dependencies:
icss-utils: ^5.1.0
postcss: ^8.4.33
@@ -4302,13 +4302,13 @@ __metadata:
semver: ^7.5.4
peerDependencies:
"@rspack/core": 0.x || 1.x
- webpack: ^5.27.0
+ webpack: ^5.0.0
peerDependenciesMeta:
"@rspack/core":
optional: true
webpack:
optional: true
- checksum: 247b07ca3f1369ec41e3c79cc59c6d97f0a473d767bf9ee563a2ee7ab404ff7f65ed4a2a3a108721250bc4055df82be6a88225f42adb360714533e37ea032da0
+ checksum: 5c8d35975a7121334905394e88e28f05df72f037dbed2fb8fec4be5f0b313ae73a13894ba791867d4a4190c35896da84a7fd0c54fb426db55d85ba5e714edbe3
languageName: node
linkType: hard
@@ -4637,10 +4637,10 @@ __metadata:
languageName: node
linkType: hard
-"devtools-protocol@npm:^0.0.1273771":
- version: 0.0.1273771
- resolution: "devtools-protocol@npm:0.0.1273771"
- checksum: 2a88694ec0f2f167f826cea8c3d6030ede911c2db79d2a62d76d1be450bcb395e8283ca03f225fa308710ab06182dced47eed8cece56b377d1946403a321b64f
+"devtools-protocol@npm:^0.0.1282316":
+ version: 0.0.1282316
+ resolution: "devtools-protocol@npm:0.0.1282316"
+ checksum: aa29d78a5b31e9e0b1bc8f7554fe2e6f1840bc4f7975fdc109442f8ef798c93e0cdddea73536b1d3b106c0a7a4771d03f324d0af0dec162649d5f46fda51c4ed
languageName: node
linkType: hard
@@ -7025,10 +7025,10 @@ __metadata:
languageName: node
linkType: hard
-"ignore@npm:^5.0.4, ignore@npm:^5.2.0, ignore@npm:^5.2.4":
- version: 5.2.4
- resolution: "ignore@npm:5.2.4"
- checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef
+"ignore@npm:^5.0.4, ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1":
+ version: 5.3.1
+ resolution: "ignore@npm:5.3.1"
+ checksum: 71d7bb4c1dbe020f915fd881108cbe85a0db3d636a0ea3ba911393c53946711d13a9b1143c7e70db06d571a5822c0a324a6bcde5c9904e7ca5047f01f1bf8cd3
languageName: node
linkType: hard
@@ -8929,7 +8929,7 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:9.0.4, minimatch@npm:^9.0.0, minimatch@npm:^9.0.1, minimatch@npm:^9.0.3":
+"minimatch@npm:9.0.4, minimatch@npm:^9.0.0, minimatch@npm:^9.0.1, minimatch@npm:^9.0.3, minimatch@npm:^9.0.4":
version: 9.0.4
resolution: "minimatch@npm:9.0.4"
dependencies:
@@ -10404,10 +10404,10 @@ __metadata:
version: 0.0.0-use.local
resolution: "performances@workspace:performances"
dependencies:
- "@types/node": 20.12.5
+ "@types/node": 20.12.7
"@types/node-forge": 1.3.11
node-forge: 1.3.1
- puppeteer: 22.6.3
+ puppeteer: 22.6.5
ts-node: 10.9.2
languageName: unknown
linkType: soft
@@ -10764,16 +10764,16 @@ __metadata:
languageName: node
linkType: hard
-"puppeteer-core@npm:22.6.3":
- version: 22.6.3
- resolution: "puppeteer-core@npm:22.6.3"
+"puppeteer-core@npm:22.6.5":
+ version: 22.6.5
+ resolution: "puppeteer-core@npm:22.6.5"
dependencies:
- "@puppeteer/browsers": 2.2.1
- chromium-bidi: 0.5.16
+ "@puppeteer/browsers": 2.2.2
+ chromium-bidi: 0.5.17
debug: 4.3.4
devtools-protocol: 0.0.1262051
ws: 8.16.0
- checksum: e81cc64cf5849d51ccecb9d450b88fb1046b360307655b8dac4ed062af3a52c8c64de778ddc6a6e0666374f6f3ee5862d958aa666979c8a193efae41e376e598
+ checksum: 4dc58083179eae79397d2c55c8cf12b27228278c5ab2d4928dd44a954af17f0f55be0b91e0e442fd282fa96574a2403e6397b3ae10bedf6ff2b38bffed164ff2
languageName: node
linkType: hard
@@ -10796,17 +10796,17 @@ __metadata:
languageName: node
linkType: hard
-"puppeteer@npm:22.6.3":
- version: 22.6.3
- resolution: "puppeteer@npm:22.6.3"
+"puppeteer@npm:22.6.5":
+ version: 22.6.5
+ resolution: "puppeteer@npm:22.6.5"
dependencies:
- "@puppeteer/browsers": 2.2.1
+ "@puppeteer/browsers": 2.2.2
cosmiconfig: 9.0.0
devtools-protocol: 0.0.1262051
- puppeteer-core: 22.6.3
+ puppeteer-core: 22.6.5
bin:
puppeteer: lib/esm/puppeteer/node/cli.js
- checksum: 9f88ead64c1422031a01ab9416e41073fefa3e27e566a43ea84025e4cb1b0794970d661ca287a00c3582a26fac2ce2147124992b8f0fc852895e465f515f12b4
+ checksum: d6361ae4e5dd7c55e244b98aca345745b147c434b3636896e1f01103de2994c48274a0ed2febf8ba917692f086d44e4d9a820007acc814e5dba7e8d18ad1aedd
languageName: node
linkType: hard
@@ -12283,12 +12283,12 @@ __metadata:
languageName: node
linkType: hard
-"style-loader@npm:3.3.4":
- version: 3.3.4
- resolution: "style-loader@npm:3.3.4"
+"style-loader@npm:4.0.0":
+ version: 4.0.0
+ resolution: "style-loader@npm:4.0.0"
peerDependencies:
- webpack: ^5.0.0
- checksum: caac3f2fe2c3c89e49b7a2a9329e1cfa515ecf5f36b9c4885f9b218019fda207a9029939b2c35821dec177a264a007e7c391ccdd3ff7401881ce6287b9c8f38b
+ webpack: ^5.27.0
+ checksum: 0b751b4cc8394a2fe1df6194bb2f6dd68e859e36f22030994bb7b5220f24f9efb5705e78b2442226e6fa4c90f74b397529c7eb0a1d7326fb016e1e140e90151c
languageName: node
linkType: hard
@@ -12595,12 +12595,12 @@ __metadata:
languageName: node
linkType: hard
-"ts-api-utils@npm:^1.0.1":
- version: 1.0.3
- resolution: "ts-api-utils@npm:1.0.3"
+"ts-api-utils@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "ts-api-utils@npm:1.3.0"
peerDependencies:
typescript: ">=4.2.0"
- checksum: 441cc4489d65fd515ae6b0f4eb8690057add6f3b6a63a36073753547fb6ce0c9ea0e0530220a0b282b0eec535f52c4dfc315d35f8a4c9a91c0def0707a714ca6
+ checksum: c746ddabfdffbf16cb0b0db32bb287236a19e583057f8649ee7c49995bb776e1d3ef384685181c11a1a480369e022ca97512cb08c517b2d2bd82c83754c97012
languageName: node
linkType: hard
@@ -12884,23 +12884,23 @@ __metadata:
languageName: node
linkType: hard
-"typescript@npm:5.4.4, typescript@npm:>=3 < 6":
- version: 5.4.4
- resolution: "typescript@npm:5.4.4"
+"typescript@npm:5.4.5, typescript@npm:>=3 < 6":
+ version: 5.4.5
+ resolution: "typescript@npm:5.4.5"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
- checksum: a7b54515d2adfc75c8d14188af0216b6b9ae3c192c9732797c24b1d14608eac1c83be7b1c65ce6f4ced0f2c40583f11b495fe1ba3d982afadbcc523517d183c8
+ checksum: 53c879c6fa1e3bcb194b274d4501ba1985894b2c2692fa079db03c5a5a7140587a1e04e1ba03184605d35f439b40192d9e138eb3279ca8eee313c081c8bcd9b0
languageName: node
linkType: hard
-"typescript@patch:typescript@5.4.4#~builtin, typescript@patch:typescript@>=3 < 6#~builtin":
- version: 5.4.4
- resolution: "typescript@patch:typescript@npm%3A5.4.4#~builtin::version=5.4.4&hash=5adc0c"
+"typescript@patch:typescript@5.4.5#~builtin, typescript@patch:typescript@>=3 < 6#~builtin":
+ version: 5.4.5
+ resolution: "typescript@patch:typescript@npm%3A5.4.5#~builtin::version=5.4.5&hash=5adc0c"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
- checksum: f64e07e11f787a18b5b98cbe7506465a5a92f56bbd4691977cc9c690f4ec49ebce51dfac77728dc792b743f8d89e8d99004370f5c96f7f56947c25c3f90f9350
+ checksum: d59e26e74f6b444517d0ba16e0ee16e75c652c2b49a59f2ebdbeb16647a855fd50c7fc786a58987e45f03bce0677092e2dd3333649fd53b11d0b0d271455837c
languageName: node
linkType: hard
@@ -13273,41 +13273,41 @@ __metadata:
languageName: node
linkType: hard
-"webdriver@npm:8.35.0":
- version: 8.35.0
- resolution: "webdriver@npm:8.35.0"
+"webdriver@npm:8.36.0":
+ version: 8.36.0
+ resolution: "webdriver@npm:8.36.0"
dependencies:
"@types/node": ^20.1.0
"@types/ws": ^8.5.3
- "@wdio/config": 8.35.0
+ "@wdio/config": 8.36.0
"@wdio/logger": 8.28.0
"@wdio/protocols": 8.32.0
- "@wdio/types": 8.32.4
- "@wdio/utils": 8.35.0
+ "@wdio/types": 8.36.0
+ "@wdio/utils": 8.36.0
deepmerge-ts: ^5.1.0
got: ^12.6.1
ky: ^0.33.0
ws: ^8.8.0
- checksum: 509940dabd6df49aae711e271185580de8daf9b9a3512141eb36e55af0484ca618d2dd45b64cec010cfb34548aaccaa48d59ce8426ab456e66906f60fe022332
+ checksum: dc438eeefb6b2848a6c61c99505cbc8b98c6fa248a0684a5e69920f24e1a1a582a63f4a2afe22591b8894ca251d19aa6d9ab194b937cb9a7b4dd907035d6395f
languageName: node
linkType: hard
-"webdriverio@npm:8.35.1, webdriverio@npm:^8.29.3":
- version: 8.35.1
- resolution: "webdriverio@npm:8.35.1"
+"webdriverio@npm:8.36.0, webdriverio@npm:^8.29.3":
+ version: 8.36.0
+ resolution: "webdriverio@npm:8.36.0"
dependencies:
"@types/node": ^20.1.0
- "@wdio/config": 8.35.0
+ "@wdio/config": 8.36.0
"@wdio/logger": 8.28.0
"@wdio/protocols": 8.32.0
"@wdio/repl": 8.24.12
- "@wdio/types": 8.32.4
- "@wdio/utils": 8.35.0
+ "@wdio/types": 8.36.0
+ "@wdio/utils": 8.36.0
archiver: ^7.0.0
aria-query: ^5.0.0
css-shorthand-properties: ^1.1.1
css-value: ^0.0.1
- devtools-protocol: ^0.0.1273771
+ devtools-protocol: ^0.0.1282316
grapheme-splitter: ^1.0.2
import-meta-resolve: ^4.0.0
is-plain-obj: ^4.1.0
@@ -13319,13 +13319,13 @@ __metadata:
resq: ^1.9.1
rgb2hex: 0.2.5
serialize-error: ^11.0.1
- webdriver: 8.35.0
+ webdriver: 8.36.0
peerDependencies:
devtools: ^8.14.0
peerDependenciesMeta:
devtools:
optional: true
- checksum: 95688b779fe1c2a8136eb256cb126ebe7ae3743b5f8278b547086c59a5502cdc641a055e25b5603e917f21337058267bc133410a577ff41ef368aa37e9768232
+ checksum: ba1de8f110a3a0208c966037aaab36ec3c1c66efdf1f1127d1c1c7448a200acc85f7bc522918bf70403bd167e072015db7871112019eb53eda3894de692fc9fd
languageName: node
linkType: hard