diff --git a/package.json b/package.json index f4d64c5e8e..938c458c37 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "connect-busboy": "1.0.0", "cors": "2.8.5", "emoji-name-map": "1.2.9", + "esbuild": "0.23.1", + "esbuild-plugin-tsc": "0.4.0", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-module-utils": "2.11.0", diff --git a/packages/core/src/domain/telemetry/telemetry.ts b/packages/core/src/domain/telemetry/telemetry.ts index e748abe3bf..684065a703 100644 --- a/packages/core/src/domain/telemetry/telemetry.ts +++ b/packages/core/src/domain/telemetry/telemetry.ts @@ -45,7 +45,7 @@ export const enum TelemetryService { } export interface Telemetry { - setContextProvider: (provider: () => Context) => void + onTelemetryEvent: (callback: (event: TelemetryEvent) => void) => void observable: Observable enabled: boolean } @@ -59,7 +59,7 @@ let onRawTelemetryEventCollected = (event: RawTelemetryEvent) => { } export function startTelemetry(telemetryService: TelemetryService, configuration: Configuration): Telemetry { - let contextProvider: () => Context + let telemetryEventCallback: (event: TelemetryEvent) => void const observable = new Observable() const alreadySentEvents = new Set() @@ -93,29 +93,29 @@ export function startTelemetry(telemetryService: TelemetryService, configuration event: RawTelemetryEvent, runtimeEnvInfo: RuntimeEnvInfo ): TelemetryEvent & Context { - return combine( - { - type: 'telemetry' as const, - date: timeStampNow(), - service: telemetryService, - version: __BUILD_ENV__SDK_VERSION__, - source: 'browser' as const, - _dd: { - format_version: 2 as const, - }, - telemetry: combine(event, { - runtime_env: runtimeEnvInfo, - connectivity: getConnectivity(), - }), - experimental_features: arrayFrom(getExperimentalFeatures()), + const telemetryEvent = { + type: 'telemetry' as const, + date: timeStampNow(), + service: telemetryService, + version: __BUILD_ENV__SDK_VERSION__, + source: 'browser' as const, + _dd: { + format_version: 2 as const, }, - contextProvider !== undefined ? contextProvider() : {} - ) as TelemetryEvent & Context + telemetry: combine(event, { + runtime_env: runtimeEnvInfo, + connectivity: getConnectivity(), + }), + experimental_features: arrayFrom(getExperimentalFeatures()), + } as TelemetryEvent & Context + telemetryEventCallback(telemetryEvent) + + return telemetryEvent } return { - setContextProvider: (provider: () => Context) => { - contextProvider = provider + onTelemetryEvent: (callback: (event: TelemetryEvent) => void) => { + telemetryEventCallback = callback }, observable, enabled: telemetryEnabled, diff --git a/packages/core/tsconfig.esm.json b/packages/core/tsconfig.esm.json index fee4f61227..b979d25c7d 100644 --- a/packages/core/tsconfig.esm.json +++ b/packages/core/tsconfig.esm.json @@ -3,7 +3,7 @@ "compilerOptions": { "baseUrl": ".", "declaration": true, - "module": "es6", + "module": "es2020", "rootDir": "./src/", "outDir": "./esm/" }, diff --git a/packages/logs/src/domain/logsTelemetry.ts b/packages/logs/src/domain/logsTelemetry.ts index d8342b1b94..978f40870b 100644 --- a/packages/logs/src/domain/logsTelemetry.ts +++ b/packages/logs/src/domain/logsTelemetry.ts @@ -9,6 +9,7 @@ import { isTelemetryReplicationAllowed, addTelemetryConfiguration, drainPreStartTelemetry, + assign, } from '@datadog/browser-core' import type { LogsConfiguration, LogsInitConfiguration } from './configuration' import { getRUMInternalContext } from './contexts/rumInternalContext' @@ -23,20 +24,22 @@ export function startLogsTelemetry( session: LogsSessionManager ) { const telemetry = startTelemetry(TelemetryService.LOGS, configuration) - telemetry.setContextProvider(() => ({ - application: { - id: getRUMInternalContext()?.application_id, - }, - session: { - id: session.findTrackedSession()?.id, - }, - view: { - id: (getRUMInternalContext()?.view as Context)?.id, - }, - action: { - id: (getRUMInternalContext()?.user_action as Context)?.id, - }, - })) + telemetry.onTelemetryEvent((telemetryEvent) => + assign(telemetryEvent, { + application: { + id: getRUMInternalContext()?.application_id, + }, + session: { + id: session.findTrackedSession()?.id, + }, + view: { + id: (getRUMInternalContext()?.view as Context)?.id, + }, + action: { + id: (getRUMInternalContext()?.user_action as Context)?.id, + }, + }) + ) const cleanupTasks: Array<() => void> = [] if (canUseEventBridge()) { const bridge = getEventBridge<'internal_telemetry', TelemetryEvent>()! diff --git a/packages/logs/tsconfig.esm.json b/packages/logs/tsconfig.esm.json index fee4f61227..b979d25c7d 100644 --- a/packages/logs/tsconfig.esm.json +++ b/packages/logs/tsconfig.esm.json @@ -3,7 +3,7 @@ "compilerOptions": { "baseUrl": ".", "declaration": true, - "module": "es6", + "module": "es2020", "rootDir": "./src/", "outDir": "./esm/" }, diff --git a/packages/rum-core/src/boot/preStartRum.ts b/packages/rum-core/src/boot/preStartRum.ts index 806947d35f..dc8943427d 100644 --- a/packages/rum-core/src/boot/preStartRum.ts +++ b/packages/rum-core/src/boot/preStartRum.ts @@ -26,8 +26,9 @@ import type { ViewOptions } from '../domain/view/trackViews' import type { DurationVital, CustomVitalsState } from '../domain/vital/vitalCollection' import { startDurationVital, stopDurationVital } from '../domain/vital/vitalCollection' import { fetchAndApplyRemoteConfiguration, serializeRumConfiguration } from '../domain/configuration' -import { callPluginsMethod } from '../domain/plugins' -import type { RumPublicApiOptions, Strategy } from './rumPublicApi' +import type { RumPlugin } from '../domain/plugins' +import { callPluginsMethod, loadLazyPlugins } from '../domain/plugins' +import type { RumPublicApi, RumPublicApiOptions, Strategy } from './rumPublicApi' import type { StartRumResult } from './startRum' export function createPreStartStrategy( @@ -38,7 +39,8 @@ export function createPreStartStrategy( doStartRum: ( configuration: RumConfiguration, deflateWorker: DeflateWorker | undefined, - initialViewOptions?: ViewOptions + initialViewOptions?: ViewOptions, + plugins?: RumPlugin[] ) => StartRumResult ): Strategy { const bufferApiCalls = createBoundedBuffer() @@ -50,6 +52,7 @@ export function createPreStartStrategy( let cachedInitConfiguration: RumInitConfiguration | undefined let cachedConfiguration: RumConfiguration | undefined + let plugins: RumPlugin[] = [] const trackingConsentStateSubscription = trackingConsentState.observable.subscribe(tryStartRum) @@ -76,12 +79,12 @@ export function createPreStartStrategy( initialViewOptions = firstStartViewCall.options } - const startRumResult = doStartRum(cachedConfiguration, deflateWorker, initialViewOptions) + const startRumResult = doStartRum(cachedConfiguration, deflateWorker, initialViewOptions, plugins) bufferApiCalls.drain(startRumResult) } - function doInit(initConfiguration: RumInitConfiguration) { + async function doInit(initConfiguration: RumInitConfiguration, publicApi: RumPublicApi) { const eventBridgeAvailable = canUseEventBridge() if (eventBridgeAvailable) { initConfiguration = overrideInitConfigurationForBridge(initConfiguration) @@ -121,11 +124,19 @@ export function createPreStartStrategy( } } + const lazyLoadedPlugins = await loadLazyPlugins(['action']) // look at how to pass the required plugins from the init config + if (!lazyLoadedPlugins) { + return + } + plugins = lazyLoadedPlugins.concat(configuration.plugins ?? []) + + callPluginsMethod(plugins, 'onInit', { initConfiguration, publicApi }) + cachedConfiguration = configuration - // Instrumuent fetch to track network requests - // This is needed in case the consent is not granted and some cutsomer - // library (Apollo Client) is storing uninstrumented fetch to be used later - // The subscrption is needed so that the instrumentation process is completed + // Instrument fetch to track network requests + // This is needed in case the consent is not granted and some customer + // library (Apollo Client) is storing un-instrumented fetch to be used later + // The subscription is needed so that the instrumentation process is completed initFetchObservable().subscribe(noop) trackingConsentState.tryToInit(configuration.trackingConsent) @@ -137,7 +148,8 @@ export function createPreStartStrategy( } return { - init(initConfiguration, publicApi) { + // eslint-disable-next-line @typescript-eslint/no-misused-promises + async init(initConfiguration, publicApi) { if (!initConfiguration) { display.error('Missing configuration') return @@ -156,16 +168,18 @@ export function createPreStartStrategy( return } - callPluginsMethod(initConfiguration.betaPlugins, 'onInit', { initConfiguration, publicApi }) - if ( initConfiguration.remoteConfigurationId && isExperimentalFeatureEnabled(ExperimentalFeature.REMOTE_CONFIGURATION) ) { - fetchAndApplyRemoteConfiguration(initConfiguration, doInit) - } else { - doInit(initConfiguration) + const overriddenConfiguration = await fetchAndApplyRemoteConfiguration(initConfiguration) + if (!overriddenConfiguration) { + return + } + initConfiguration = overriddenConfiguration } + + await doInit(initConfiguration, publicApi) }, get initConfiguration() { diff --git a/packages/rum-core/src/boot/rumPublicApi.ts b/packages/rum-core/src/boot/rumPublicApi.ts index 1c8db3989a..2475d91111 100644 --- a/packages/rum-core/src/boot/rumPublicApi.ts +++ b/packages/rum-core/src/boot/rumPublicApi.ts @@ -357,7 +357,7 @@ export function makeRumPublicApi( getCommonContext, trackingConsentState, customVitalsState, - (configuration, deflateWorker, initialViewOptions) => { + (configuration, deflateWorker, initialViewOptions, plugins) => { if (isExperimentalFeatureEnabled(ExperimentalFeature.UPDATE_VIEW_NAME)) { /** * Update View Name. @@ -390,7 +390,8 @@ export function makeRumPublicApi( ? (streamId) => options.createDeflateEncoder!(configuration, deflateWorker, streamId) : createIdentityEncoder, trackingConsentState, - customVitalsState + customVitalsState, + plugins ) recorderApi.onRumStart( diff --git a/packages/rum-core/src/boot/startRum.ts b/packages/rum-core/src/boot/startRum.ts index 029c044dd6..9ed058727b 100644 --- a/packages/rum-core/src/boot/startRum.ts +++ b/packages/rum-core/src/boot/startRum.ts @@ -19,6 +19,7 @@ import { drainPreStartTelemetry, isExperimentalFeatureEnabled, ExperimentalFeature, + assign, } from '@datadog/browser-core' import { createDOMMutationObservable } from '../browser/domMutationObservable' import { startPerformanceCollection } from '../browser/performanceCollection' @@ -27,10 +28,8 @@ import { startInternalContext } from '../domain/contexts/internalContext' import { LifeCycle, LifeCycleEventType } from '../domain/lifeCycle' import { startViewContexts } from '../domain/contexts/viewContexts' import { startRequestCollection } from '../domain/requestCollection' -import { startActionCollection } from '../domain/action/actionCollection' import { startErrorCollection } from '../domain/error/errorCollection' import { startLongTaskCollection } from '../domain/longTask/longTaskCollection' -import { startResourceCollection } from '../domain/resource/resourceCollection' import { startViewCollection } from '../domain/view/viewCollection' import type { RumSessionManager } from '../domain/rumSessionManager' import { startRumSessionManager, startRumSessionManagerStub } from '../domain/rumSessionManager' @@ -50,11 +49,14 @@ import { startDisplayContext } from '../domain/contexts/displayContext' import type { CustomVitalsState } from '../domain/vital/vitalCollection' import { startVitalCollection } from '../domain/vital/vitalCollection' import { startCiVisibilityContext } from '../domain/contexts/ciVisibilityContext' +import { callPluginsMethod, getPluginsApis, type RumPlugin } from '../domain/plugins' +import type { ActionPublicApi } from '../domain/action/actionPlugin' import { startLongAnimationFrameCollection } from '../domain/longAnimationFrame/longAnimationFrameCollection' +import { startResourceCollection } from '../domain/resource/resourceCollection' import type { RecorderApi } from './rumPublicApi' -export type StartRum = typeof startRum -export type StartRumResult = ReturnType +export type StartRum = (...args: Parameters) => StartRumResult +export type StartRumResult = ReturnType & ActionPublicApi export function startRum( configuration: RumConfiguration, @@ -68,7 +70,8 @@ export function startRum( // collecting logs unconditionally. As such, `startRum` should be called with a // `trackingConsentState` set to "granted". trackingConsentState: TrackingConsentState, - customVitalsState: CustomVitalsState + customVitalsState: CustomVitalsState, + plugins: RumPlugin[] = [] ) { const cleanupTasks: Array<() => void> = [] const lifeCycle = new LifeCycle() @@ -76,20 +79,20 @@ export function startRum( lifeCycle.subscribe(LifeCycleEventType.RUM_EVENT_COLLECTED, (event) => sendToExtension('rum', event)) const telemetry = startRumTelemetry(configuration) - telemetry.setContextProvider(() => ({ - application: { - id: configuration.applicationId, - }, - session: { - id: session.findTrackedSession()?.id, - }, - view: { - id: viewContexts.findView()?.id, - }, - action: { - id: actionContexts.findActionId(), - }, - })) + telemetry.onTelemetryEvent((telemetryEvent) => { + assign(telemetryEvent, { + application: { + id: configuration.applicationId, + }, + session: { + id: session.findTrackedSession()?.id, + }, + view: { + id: viewContexts.findView()?.id, + }, + }) + callPluginsMethod(plugins, 'onTelemetryEvent', { telemetryEvent }) + }) const reportError = (error: RawError) => { lifeCycle.notify(LifeCycleEventType.RAW_ERROR_COLLECTED, { error }) @@ -131,8 +134,6 @@ export function startRum( const { viewContexts, urlContexts, - actionContexts, - addAction, stop: stopRumEventCollection, } = startRumEventCollection( lifeCycle, @@ -141,7 +142,6 @@ export function startRum( session, pageStateHistory, locationChangeObservable, - domMutationObservable, getCommonContext, reportError ) @@ -167,13 +167,23 @@ export function startRum( ) cleanupTasks.push(stopViewCollection) - const { stop: stopResourceCollection } = startResourceCollection(lifeCycle, configuration, pageStateHistory) - cleanupTasks.push(stopResourceCollection) + if (configuration.trackResources) { + // import(/* webpackChunkName: "resource" */ /* webpackMode: "lazy" */ '../domain/resource/resourceCollection').then( + // ({ startResourceCollection }) => { + const { stop: stopResourceCollection } = startResourceCollection(lifeCycle, configuration, pageStateHistory) + cleanupTasks.push(stopResourceCollection) + // } + // ) + } if (isExperimentalFeatureEnabled(ExperimentalFeature.LONG_ANIMATION_FRAME)) { if (configuration.trackLongTasks) { + // import( + // /* webpackChunkName: "long-animation-frame" */ /* webpackMode: "lazy" */ '../domain/longAnimationFrame/longAnimationFrameCollection' + // ).then(({ startLongAnimationFrameCollection }) => { const { stop: stopLongAnimationFrameCollection } = startLongAnimationFrameCollection(lifeCycle, configuration) cleanupTasks.push(stopLongAnimationFrameCollection) + // }) } } else { startLongTaskCollection(lifeCycle, configuration) @@ -186,16 +196,16 @@ export function startRum( cleanupTasks.push(stopPerformanceCollection) const vitalCollection = startVitalCollection(lifeCycle, pageStateHistory, customVitalsState) - const internalContext = startInternalContext( - configuration.applicationId, - session, - viewContexts, - actionContexts, - urlContexts - ) + const internalContext = startInternalContext(plugins, configuration.applicationId, session, viewContexts, urlContexts) - return { - addAction, + // Could be simplified with Dependency Injection + plugins + .find((plugin) => plugin.name === 'action') + ?.onStart?.(lifeCycle, configuration, domMutationObservable, pageStateHistory) + + const pluginsApis = getPluginsApis(plugins) + + return assign(pluginsApis, { addError, addTiming, addFeatureFlagEvaluation: featureFlagContexts.addFeatureFlagEvaluation, @@ -212,7 +222,7 @@ export function startRum( stop: () => { cleanupTasks.forEach((task) => task()) }, - } + }) } function startRumTelemetry(configuration: RumConfiguration) { @@ -231,20 +241,12 @@ export function startRumEventCollection( sessionManager: RumSessionManager, pageStateHistory: PageStateHistory, locationChangeObservable: Observable, - domMutationObservable: Observable, getCommonContext: () => CommonContext, reportError: (error: RawError) => void ) { const viewContexts = startViewContexts(lifeCycle) const urlContexts = startUrlContexts(lifeCycle, locationChangeObservable, location) - const { addAction, actionContexts } = startActionCollection( - lifeCycle, - domMutationObservable, - configuration, - pageStateHistory - ) - const displayContext = startDisplayContext(configuration) const ciVisibilityContext = startCiVisibilityContext(configuration) @@ -254,7 +256,6 @@ export function startRumEventCollection( sessionManager, viewContexts, urlContexts, - actionContexts, displayContext, ciVisibilityContext, getCommonContext, @@ -265,8 +266,6 @@ export function startRumEventCollection( viewContexts, pageStateHistory, urlContexts, - addAction, - actionContexts, stop: () => { ciVisibilityContext.stop() displayContext.stop() diff --git a/packages/rum-core/src/domain/action/actionCollection.ts b/packages/rum-core/src/domain/action/actionCollection.ts index 836e33c733..eff508ebad 100644 --- a/packages/rum-core/src/domain/action/actionCollection.ts +++ b/packages/rum-core/src/domain/action/actionCollection.ts @@ -1,6 +1,5 @@ import type { ClocksState, Context, Observable } from '@datadog/browser-core' import { noop, assign, combine, toServerDuration, generateUUID } from '@datadog/browser-core' - import { discardNegativeDuration } from '../discardNegativeDuration' import type { RawRumActionEvent } from '../../rawRumEvent.types' import { ActionType, RumEventType } from '../../rawRumEvent.types' @@ -57,7 +56,7 @@ export function startActionCollection( } } -function processAction( +export function processAction( action: AutoAction | CustomAction, pageStateHistory: PageStateHistory ): RawRumEventCollectedData { diff --git a/packages/rum-core/src/domain/action/actionPlugin.ts b/packages/rum-core/src/domain/action/actionPlugin.ts new file mode 100644 index 0000000000..07f7908599 --- /dev/null +++ b/packages/rum-core/src/domain/action/actionPlugin.ts @@ -0,0 +1,70 @@ +import type { Observable } from '@datadog/browser-core' +import type { RumEvent, RumErrorEvent, RumLongTaskEvent, RumResourceEvent } from '../../rumEvent.types' +import { RumEventType } from '../../rawRumEvent.types' +import type { PageStateHistory } from '../contexts/pageStateHistory' +import type { Mutable } from '../assembly' +import type { CommonContext } from '../contexts/commonContext' +import type { LifeCycle } from '../lifeCycle' +import type { RumConfiguration } from '../configuration' +import type { RumPlugin } from '../plugins' +import { startActionCollection } from './actionCollection' +import type { ActionContexts, CustomAction } from './actionCollection' + +export type ActionPublicApi = { + addAction: (action: CustomAction, savedCommonContext?: CommonContext) => void +} + +// eslint-disable-next-line local-rules/disallow-side-effects, import/no-default-export +export default function actionPlugin(): RumPlugin { + let actionContexts: ActionContexts + let addAction: ActionPublicApi['addAction'] + + return { + name: 'action', + onStart( + lifeCycle: LifeCycle, + configuration: RumConfiguration, + domMutationObservable: Observable, + pageStateHistory: PageStateHistory + ) { + ;({ actionContexts, addAction } = startActionCollection( + lifeCycle, + domMutationObservable, + configuration, + pageStateHistory + )) + }, + onEvent({ startTime, rumEvent }) { + const actionId = actionContexts.findActionId(startTime) + if (needToAssembleWithAction(rumEvent) && actionId) { + ;(rumEvent.action as Mutable) = { id: actionId } + } + }, + onTelemetryEvent({ telemetryEvent }) { + const actionId = actionContexts.findActionId() + if (actionId) { + telemetryEvent.action = { + id: actionId as string, + } + } + }, + getInternalContext({ startTime }) { + const actionId = actionContexts.findActionId(startTime) + if (actionId) { + return { user_action: { id: actionId } } + } + return {} + }, + getApi(): ActionPublicApi { + return { addAction } + }, + // could be removed in favor of onTelemetryEvent + getConfigurationTelemetry() { + return {} + }, + } satisfies RumPlugin +} + +function needToAssembleWithAction(event: RumEvent): event is RumErrorEvent | RumResourceEvent | RumLongTaskEvent { + return [RumEventType.ERROR, RumEventType.RESOURCE, RumEventType.LONG_TASK].indexOf(event.type as RumEventType) !== -1 +} diff --git a/packages/rum-core/src/domain/action/getActionNameFromElement.ts b/packages/rum-core/src/domain/action/getActionNameFromElement.ts index e3e9b5ed7d..aeb95dd3c1 100644 --- a/packages/rum-core/src/domain/action/getActionNameFromElement.ts +++ b/packages/rum-core/src/domain/action/getActionNameFromElement.ts @@ -1,14 +1,13 @@ import { safeTruncate, isIE, find } from '@datadog/browser-core' import { getParentElement } from '../../browser/polyfills' -import { NodePrivacyLevel, getPrivacySelector } from '../privacy' +import { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE, NodePrivacyLevel, getPrivacySelector } from '../privacy' import type { RumConfiguration } from '../configuration' /** * Get the action name from the attribute 'data-dd-action-name' on the element or any of its parent. * It can also be retrieved from a user defined attribute. */ -export const DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE = 'data-dd-action-name' -export const ACTION_NAME_PLACEHOLDER = 'Masked Element' +const ACTION_NAME_PLACEHOLDER = 'Masked Element' export function getActionNameFromElement( element: Element, { enablePrivacyForActionName, actionNameAttribute: userProgrammaticAttribute }: RumConfiguration, diff --git a/packages/rum-core/src/domain/assembly.ts b/packages/rum-core/src/domain/assembly.ts index 69810192a5..18b3cdce10 100644 --- a/packages/rum-core/src/domain/assembly.ts +++ b/packages/rum-core/src/domain/assembly.ts @@ -14,13 +14,7 @@ import { getConnectivity, } from '@datadog/browser-core' import type { RumEventDomainContext } from '../domainContext.types' -import type { - RawRumErrorEvent, - RawRumEvent, - RawRumLongTaskEvent, - RawRumResourceEvent, - RumContext, -} from '../rawRumEvent.types' +import type { RumContext } from '../rawRumEvent.types' import { RumEventType } from '../rawRumEvent.types' import type { RumEvent } from '../rumEvent.types' import { getSyntheticsContext } from './contexts/syntheticsContext' @@ -31,11 +25,11 @@ import type { ViewContexts } from './contexts/viewContexts' import { SessionReplayState, type RumSessionManager } from './rumSessionManager' import type { UrlContexts } from './contexts/urlContexts' import type { RumConfiguration } from './configuration' -import type { ActionContexts } from './action/actionCollection' import type { DisplayContext } from './contexts/displayContext' import type { CommonContext } from './contexts/commonContext' import type { ModifiableFieldPaths } from './limitModification' import { limitModification } from './limitModification' +import { callPluginsMethod } from './plugins' // replaced at build time declare const __BUILD_ENV__SDK_VERSION__: string @@ -63,7 +57,7 @@ const ROOT_MODIFIABLE_FIELD_PATHS: ModifiableFieldPaths = { let modifiableFieldPathsByEvent: { [key in RumEventType]: ModifiableFieldPaths } -type Mutable = { -readonly [P in keyof T]: T[P] } +export type Mutable = { -readonly [P in keyof T]: T[P] } export function startRumAssembly( configuration: RumConfiguration, @@ -71,7 +65,6 @@ export function startRumAssembly( sessionManager: RumSessionManager, viewContexts: ViewContexts, urlContexts: UrlContexts, - actionContexts: ActionContexts, displayContext: DisplayContext, ciVisibilityContext: CiVisibilityContext, getCommonContext: () => CommonContext, @@ -143,7 +136,6 @@ export function startRumAssembly( const session = sessionManager.findTrackedSession(startTime) if (session && viewContext && urlContext) { const commonContext = savedCommonContext || getCommonContext() - const actionId = actionContexts.findActionId(startTime) const rumContext: RumContext = { _dd: { @@ -176,7 +168,6 @@ export function startRumAssembly( url: urlContext.url, referrer: urlContext.referrer, }, - action: needToAssembleWithAction(rawRumEvent) && actionId ? { id: actionId } : undefined, synthetics: syntheticsContext, ci_test: ciVisibilityContext.get(), display: displayContext.get(), @@ -186,6 +177,8 @@ export function startRumAssembly( const serverRumEvent = combine(rumContext as RumContext & Context, rawRumEvent) as RumEvent & Context serverRumEvent.context = combine(commonContext.context, viewContext.customerContext, customerContext) + callPluginsMethod(configuration.plugins, 'onEvent', { startTime, rumEvent: serverRumEvent }) + if (!('has_replay' in serverRumEvent.session)) { ;(serverRumEvent.session as Mutable).has_replay = commonContext.hasReplay } @@ -231,9 +224,3 @@ function shouldSend( return !rateLimitReached } - -function needToAssembleWithAction( - event: RawRumEvent -): event is RawRumErrorEvent | RawRumResourceEvent | RawRumLongTaskEvent { - return [RumEventType.ERROR, RumEventType.RESOURCE, RumEventType.LONG_TASK].indexOf(event.type) !== -1 -} diff --git a/packages/rum-core/src/domain/configuration/remoteConfiguration.ts b/packages/rum-core/src/domain/configuration/remoteConfiguration.ts index c2e0bb9722..6b236e283f 100644 --- a/packages/rum-core/src/domain/configuration/remoteConfiguration.ts +++ b/packages/rum-core/src/domain/configuration/remoteConfiguration.ts @@ -1,5 +1,5 @@ import type { DefaultPrivacyLevel } from '@datadog/browser-core' -import { display, addEventListener, assign } from '@datadog/browser-core' +import { display, assign } from '@datadog/browser-core' import type { RumInitConfiguration } from './configuration' export const REMOTE_CONFIGURATION_URL = 'https://d3uc069fcn7uxw.cloudfront.net/configuration' @@ -10,13 +10,14 @@ export interface RumRemoteConfiguration { defaultPrivacyLevel?: DefaultPrivacyLevel } -export function fetchAndApplyRemoteConfiguration( - initConfiguration: RumInitConfiguration, - callback: (initConfiguration: RumInitConfiguration) => void -) { - fetchRemoteConfiguration(initConfiguration, (remoteInitConfiguration) => { - callback(applyRemoteConfiguration(initConfiguration, remoteInitConfiguration)) - }) +export async function fetchAndApplyRemoteConfiguration( + initConfiguration: RumInitConfiguration +): Promise { + const remoteConfiguration = await fetchRemoteConfiguration(initConfiguration) + if (!remoteConfiguration) { + return + } + return applyRemoteConfiguration(initConfiguration, remoteConfiguration) } export function applyRemoteConfiguration( @@ -26,26 +27,21 @@ export function applyRemoteConfiguration( return assign({}, initConfiguration, remoteInitConfiguration) } -export function fetchRemoteConfiguration( - configuration: RumInitConfiguration, - callback: (remoteConfiguration: RumRemoteConfiguration) => void -) { - const xhr = new XMLHttpRequest() +export async function fetchRemoteConfiguration( + configuration: RumInitConfiguration +): Promise { + try { + const response = await fetch( + `${REMOTE_CONFIGURATION_URL}/${encodeURIComponent(configuration.remoteConfigurationId!)}.json` + ) - addEventListener(configuration, xhr, 'load', function () { - if (xhr.status === 200) { - callback(JSON.parse(xhr.responseText)) - } else { + if (!response.ok) { displayRemoteConfigurationFetchingError() } - }) - - addEventListener(configuration, xhr, 'error', function () { + return (await response.json()) as RumRemoteConfiguration + } catch (error) { displayRemoteConfigurationFetchingError() - }) - - xhr.open('GET', `${REMOTE_CONFIGURATION_URL}/${encodeURIComponent(configuration.remoteConfigurationId!)}.json`) - xhr.send() + } } function displayRemoteConfigurationFetchingError() { diff --git a/packages/rum-core/src/domain/contexts/internalContext.ts b/packages/rum-core/src/domain/contexts/internalContext.ts index f6df1794bd..31ef129571 100644 --- a/packages/rum-core/src/domain/contexts/internalContext.ts +++ b/packages/rum-core/src/domain/contexts/internalContext.ts @@ -1,6 +1,7 @@ -import type { RelativeTime } from '@datadog/browser-core' -import type { ActionContexts } from '../action/actionCollection' +import { assign, type RelativeTime } from '@datadog/browser-core' import type { RumSessionManager } from '../rumSessionManager' +import type { RumPlugin } from '../plugins' +import { getPluginsInternalContext } from '../plugins' import type { ViewContexts } from './viewContexts' import type { UrlContexts } from './urlContexts' @@ -23,10 +24,10 @@ export interface InternalContext { * to not break compatibility with logs data format */ export function startInternalContext( + plugins: RumPlugin[], applicationId: string, sessionManager: RumSessionManager, viewContexts: ViewContexts, - actionContexts: ActionContexts, urlContexts: UrlContexts ) { return { @@ -35,13 +36,14 @@ export function startInternalContext( const urlContext = urlContexts.findUrl(startTime as RelativeTime) const session = sessionManager.findTrackedSession(startTime as RelativeTime) if (session && viewContext && urlContext) { - const actionId = actionContexts.findActionId(startTime as RelativeTime) - return { + const pluginsInternalContext = getPluginsInternalContext(plugins, startTime as RelativeTime) + const internalContext = assign(pluginsInternalContext, { application_id: applicationId, session_id: session.id, - user_action: actionId ? { id: actionId } : undefined, view: { id: viewContext.id, name: viewContext.name, referrer: urlContext.referrer, url: urlContext.url }, - } + }) + + return internalContext } }, } diff --git a/packages/rum-core/src/domain/getSelectorFromElement.ts b/packages/rum-core/src/domain/getSelectorFromElement.ts index fff50d7433..84a95a5641 100644 --- a/packages/rum-core/src/domain/getSelectorFromElement.ts +++ b/packages/rum-core/src/domain/getSelectorFromElement.ts @@ -1,5 +1,5 @@ import { cssEscape, elementMatches, getClassList, getParentElement } from '../browser/polyfills' -import { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './action/getActionNameFromElement' +import { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './privacy' /** * Stable attributes are attributes that are commonly used to identify parts of a UI (ex: diff --git a/packages/rum-core/src/domain/plugins.ts b/packages/rum-core/src/domain/plugins.ts index d6e1dd63ca..0436342788 100644 --- a/packages/rum-core/src/domain/plugins.ts +++ b/packages/rum-core/src/domain/plugins.ts @@ -1,13 +1,25 @@ +import { assign, display } from '@datadog/browser-core' +import type { TelemetryEvent, Context, RelativeTime } from '@datadog/browser-core' import type { RumPublicApi } from '../boot/rumPublicApi' +import type { RumEvent } from '../rumEvent.types' import type { RumInitConfiguration } from './configuration' +export const PLUGINS_NAMES = ['action'] as const + export interface RumPlugin { name: string + getApi?(): { [key: string]: any } getConfigurationTelemetry?(): Record + getInternalContext?(options: { startTime: RelativeTime }): Context + onInit?(options: { initConfiguration: RumInitConfiguration; publicApi: RumPublicApi }): void + onStart?(...args: any[]): void + onEvent?(options: { startTime: RelativeTime; rumEvent: RumEvent & Context }): void + onTelemetryEvent?(options: { telemetryEvent: TelemetryEvent }): void } -type MethodNames = 'onInit' +type MethodNames = 'onInit' | 'onStart' | 'onEvent' | 'onTelemetryEvent' + type MethodParameter = Parameters>[0] export function callPluginsMethod( @@ -25,3 +37,44 @@ export function callPluginsMethod( } } } + +export function getPluginsInternalContext(plugins: RumPlugin[], startTime: RelativeTime): Context { + const internalContexts = plugins.reduce( + (context, plugin) => assign(context, plugin.getInternalContext?.({ startTime })), + {} + ) + return internalContexts +} + +export function getPluginsApis(plugins: RumPlugin[]): Context { + const apis = plugins.reduce((context, plugin) => assign(context, plugin.getApi?.()), {}) + return apis +} + +const lazyPluginPaths = { + // eslint-disable-next-line import/no-cycle + action: () => import(/* webpackChunkName: "action" */ /* webpackMode: "lazy" */ './action/actionPlugin'), +} + +type LazyPluginKeys = keyof typeof lazyPluginPaths + +export async function loadLazyPlugins(pluginNames: LazyPluginKeys[]): Promise { + const pluginPaths = pluginNames.map((name) => lazyPluginPaths[name]) + + try { + const plugins = await Promise.all( + pluginPaths.map(async (path) => { + const { default: createPlugin } = await path() + return createPlugin() + }) + ) + return plugins + } catch (e) { + displayLazyPluginFetchingError() + return undefined + } +} + +function displayLazyPluginFetchingError() { + display.error('Error fetching the Browser SDK plugins.') +} diff --git a/packages/rum-core/src/domain/privacy.ts b/packages/rum-core/src/domain/privacy.ts index 512b65cb0b..548424695f 100644 --- a/packages/rum-core/src/domain/privacy.ts +++ b/packages/rum-core/src/domain/privacy.ts @@ -2,6 +2,8 @@ import { DefaultPrivacyLevel } from '@datadog/browser-core' import { isElementNode, getParentNode, isTextNode } from '../browser/htmlDomUtils' import { elementMatches } from '../browser/polyfills' +export const DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE = 'data-dd-action-name' + export const NodePrivacyLevel = { IGNORE: 'ignore', HIDDEN: 'hidden', diff --git a/packages/rum-core/src/index.ts b/packages/rum-core/src/index.ts index 1292120b31..0308db8ce2 100644 --- a/packages/rum-core/src/index.ts +++ b/packages/rum-core/src/index.ts @@ -30,7 +30,6 @@ export { getMutationObserverConstructor } from './browser/domMutationObservable' export { initViewportObservable, getViewportDimension, ViewportDimension } from './browser/viewportObservable' export { getScrollX, getScrollY } from './browser/scroll' export { RumInitConfiguration, RumConfiguration, RumRemoteConfiguration } from './domain/configuration' -export { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './domain/action/getActionNameFromElement' export { STABLE_ATTRIBUTES } from './domain/getSelectorFromElement' export * from './browser/htmlDomUtils' export * from './browser/polyfills' diff --git a/packages/rum-core/tsconfig.esm.json b/packages/rum-core/tsconfig.esm.json index fee4f61227..b979d25c7d 100644 --- a/packages/rum-core/tsconfig.esm.json +++ b/packages/rum-core/tsconfig.esm.json @@ -3,7 +3,7 @@ "compilerOptions": { "baseUrl": ".", "declaration": true, - "module": "es6", + "module": "es2020", "rootDir": "./src/", "outDir": "./esm/" }, diff --git a/packages/rum/esbuild.build.js b/packages/rum/esbuild.build.js new file mode 100644 index 0000000000..379f731f9f --- /dev/null +++ b/packages/rum/esbuild.build.js @@ -0,0 +1,20 @@ +const fs = require('fs') +const esbuild = require('esbuild') + +esbuild + .build({ + entryPoints: ['src/entries/main.ts'], + outdir: './bundle', + bundle: true, + minify: true, + metafile: true, + sourcemap: true, + splitting: true, + format: 'esm', + }) + .then((result) => { + fs.writeFileSync('meta.json', JSON.stringify(result.metafile)) + }) + .catch(() => { + console.log('error') + }) diff --git a/packages/rum/package.json b/packages/rum/package.json index b14a4887dd..8b8be3ab2c 100644 --- a/packages/rum/package.json +++ b/packages/rum/package.json @@ -8,6 +8,7 @@ "scripts": { "build": "run-p build:cjs build:esm build:bundle", "build:bundle": "rm -rf bundle && webpack --mode=production", + "build:bundle:esbuild": "rm -rf bundle && node ./esbuild.build.js", "build:cjs": "rm -rf cjs && tsc -p tsconfig.cjs.json && yarn replace-build-env cjs", "build:esm": "rm -rf esm && tsc -p tsconfig.esm.json && yarn replace-build-env esm", "replace-build-env": "node ../../scripts/build/replace-build-env.js" @@ -33,7 +34,10 @@ "devDependencies": { "@types/pako": "2.0.3", "@types/webpack-bundle-analyzer": "^4", - "pako": "2.1.0" + "esbuild": "0.23.1", + "esbuild-plugin-compressor": "1.0.1", + "pako": "2.1.0", + "typescript": "5.6.2" }, "volta": { "extends": "../../package.json" diff --git a/packages/rum/src/entries/internalSynthetics.ts b/packages/rum/src/entries/internalSynthetics.ts index 7890cac0fe..bbe6270cd5 100644 --- a/packages/rum/src/entries/internalSynthetics.ts +++ b/packages/rum/src/entries/internalSynthetics.ts @@ -5,6 +5,7 @@ * WARNING: this module is not intended for public usages, and won't follow semver for breaking * changes. */ +import type { StartRum } from '@datadog/browser-rum-core' import { makeRumPublicApi, startRum } from '@datadog/browser-rum-core' import { startRecording } from '../boot/startRecording' @@ -16,5 +17,7 @@ export { DefaultPrivacyLevel } from '@datadog/browser-core' // have side effects. /* eslint-disable local-rules/disallow-side-effects */ const recorderApi = makeRecorderApi(startRecording) -export const datadogRum = makeRumPublicApi(startRum, recorderApi, { ignoreInitIfSyntheticsWillInjectRum: false }) +export const datadogRum = makeRumPublicApi(startRum as StartRum, recorderApi, { + ignoreInitIfSyntheticsWillInjectRum: false, +}) /* eslint-enable local-rules/disallow-side-effects */ diff --git a/packages/rum/src/entries/main.ts b/packages/rum/src/entries/main.ts index 895cc7509e..884a57bb2a 100644 --- a/packages/rum/src/entries/main.ts +++ b/packages/rum/src/entries/main.ts @@ -1,6 +1,6 @@ // Keep the following in sync with packages/rum-slim/src/entries/main.ts import { defineGlobal, getGlobalObject } from '@datadog/browser-core' -import type { RumPublicApi } from '@datadog/browser-rum-core' +import type { RumPublicApi, StartRum } from '@datadog/browser-rum-core' import { makeRumPublicApi, startRum } from '@datadog/browser-rum-core' import { startRecording } from '../boot/startRecording' @@ -32,7 +32,10 @@ export { export { DefaultPrivacyLevel } from '@datadog/browser-core' const recorderApi = makeRecorderApi(startRecording) -export const datadogRum = makeRumPublicApi(startRum, recorderApi, { startDeflateWorker, createDeflateEncoder }) +export const datadogRum = makeRumPublicApi(startRum as StartRum, recorderApi, { + startDeflateWorker, + createDeflateEncoder, +}) interface BrowserWindow extends Window { DD_RUM?: RumPublicApi diff --git a/packages/rum/tsconfig.esm.json b/packages/rum/tsconfig.esm.json index 270d42a788..2439c00810 100644 --- a/packages/rum/tsconfig.esm.json +++ b/packages/rum/tsconfig.esm.json @@ -3,7 +3,7 @@ "compilerOptions": { "baseUrl": ".", "declaration": true, - "module": "es6", + "module": "es2020", "allowJs": true, "rootDir": "./src/", "outDir": "./esm/" diff --git a/packages/rum/webpack.config.js b/packages/rum/webpack.config.js index dafed60d59..c1ae1fc212 100644 --- a/packages/rum/webpack.config.js +++ b/packages/rum/webpack.config.js @@ -8,5 +8,10 @@ module.exports = (_env, argv) => mode: argv.mode, entry: path.resolve(__dirname, 'src/entries/main.ts'), filename: 'datadog-rum.js', - plugins: [new BundleAnalyzerPlugin({ generateStatsFile: true })], + plugins: [ + new BundleAnalyzerPlugin({ + generateStatsFile: true, + defaultSizes: 'gzip', // Display the gzip size of bundles + }), + ], }) diff --git a/performances/tsconfig.json b/performances/tsconfig.json index 8ff0ab28af..1c2fbeaca3 100644 --- a/performances/tsconfig.json +++ b/performances/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "baseUrl": ".", - "target": "es6", + "target": "ES2020", "lib": ["ES2019"], "types": ["node", "node-forge"] } diff --git a/sandbox/index.html b/sandbox/index.html index 20c03da615..2c08c524f5 100644 --- a/sandbox/index.html +++ b/sandbox/index.html @@ -3,7 +3,7 @@ Sandbox - + + diff --git a/tsconfig.base.json b/tsconfig.base.json index 81bec0f38e..1743153955 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -4,15 +4,15 @@ "experimentalDecorators": true, "esModuleInterop": true, "importHelpers": false, + "module": "ES2020", "moduleResolution": "node", "resolveJsonModule": true, "strict": true, - "target": "es5", + "target": "es2020", "sourceMap": true, "jsx": "react", - "types": [], - "lib": ["ES2016", "DOM"], + "lib": ["ES2020", "DOM"], "paths": { "@datadog/browser-core": ["./packages/core/src"], diff --git a/webpack.base.js b/webpack.base.js index 7470ec2f4b..5d84cfab28 100644 --- a/webpack.base.js +++ b/webpack.base.js @@ -13,7 +13,7 @@ module.exports = ({ entry, mode, filename, types, keepBuildEnvVariables, plugins filename, path: path.resolve('./bundle'), }, - target: ['web', 'es5'], + target: ['web', 'es2020'], devtool: false, module: { rules: [ diff --git a/yarn.lock b/yarn.lock index 35d11be149..17cd529c33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -388,7 +388,12 @@ __metadata: "@datadog/browser-core": "npm:5.26.0" "@datadog/browser-rum-core": "npm:5.26.0" "@types/pako": "npm:2.0.3" + "@types/webpack-bundle-analyzer": "npm:^4" + esbuild: "npm:0.23.1" + esbuild-plugin-compressor: "npm:1.0.1" pako: "npm:2.1.0" + typescript: "npm:5.6.2" + webpack-bundle-analyzer: "npm:4.10.2" peerDependencies: "@datadog/browser-logs": 5.26.0 peerDependenciesMeta: @@ -431,6 +436,13 @@ __metadata: languageName: unknown linkType: soft +"@discoveryjs/json-ext@npm:0.5.7": + version: 0.5.7 + resolution: "@discoveryjs/json-ext@npm:0.5.7" + checksum: 10c0/e10f1b02b78e4812646ddf289b7d9f2cb567d336c363b266bd50cd223cf3de7c2c74018d91cd2613041568397ef3a4a2b500aba588c6e5bd78c38374ba68f38c + languageName: node + linkType: hard + "@discoveryjs/json-ext@npm:^0.5.0": version: 0.5.2 resolution: "@discoveryjs/json-ext@npm:0.5.2" @@ -449,6 +461,174 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/aix-ppc64@npm:0.23.1" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm64@npm:0.23.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm@npm:0.23.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-x64@npm:0.23.1" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-arm64@npm:0.23.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-x64@npm:0.23.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-arm64@npm:0.23.1" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-x64@npm:0.23.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm64@npm:0.23.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm@npm:0.23.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ia32@npm:0.23.1" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-loong64@npm:0.23.1" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-mips64el@npm:0.23.1" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ppc64@npm:0.23.1" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-riscv64@npm:0.23.1" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-s390x@npm:0.23.1" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-x64@npm:0.23.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/netbsd-x64@npm:0.23.1" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-arm64@npm:0.23.1" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-x64@npm:0.23.1" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/sunos-x64@npm:0.23.1" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-arm64@npm:0.23.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-ia32@npm:0.23.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-x64@npm:0.23.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -1402,6 +1582,13 @@ __metadata: languageName: node linkType: hard +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.25 + resolution: "@polka/url@npm:1.0.0-next.25" + checksum: 10c0/ef61f0a0fe94bb6e1143fc5b9d5a12e6ca9dbd2c57843ebf81db432c21b9f1005c09e8a1ef8b6d5ddfa42146ca65b640feb2d353bd0d3546da46ba59e48a5349 + languageName: node + linkType: hard + "@puppeteer/browsers@npm:1.9.1, @puppeteer/browsers@npm:^1.6.0": version: 1.9.1 resolution: "@puppeteer/browsers@npm:1.9.1" @@ -1991,6 +2178,17 @@ __metadata: languageName: node linkType: hard +"@types/webpack-bundle-analyzer@npm:^4": + version: 4.7.0 + resolution: "@types/webpack-bundle-analyzer@npm:4.7.0" + dependencies: + "@types/node": "npm:*" + tapable: "npm:^2.2.0" + webpack: "npm:^5" + checksum: 10c0/dd5294ab9654081848066b14b8f01fcabb61b0e3ed4975f1613cc5da0f473b4496164a3fce3ac63027a15bb2f27d9442562f5099e764d6c03f72fe5a69fcc9bc + languageName: node + linkType: hard + "@types/which@npm:^2.0.1": version: 2.0.2 resolution: "@types/which@npm:2.0.2" @@ -2729,6 +2927,15 @@ __metadata: languageName: node linkType: hard +"acorn-walk@npm:^8.0.0": + version: 8.3.4 + resolution: "acorn-walk@npm:8.3.4" + dependencies: + acorn: "npm:^8.11.0" + checksum: 10c0/76537ac5fb2c37a64560feaf3342023dadc086c46da57da363e64c6148dc21b57d49ace26f949e225063acb6fb441eabffd89f7a3066de5ad37ab3e328927c62 + languageName: node + linkType: hard + "acorn-walk@npm:^8.1.1": version: 8.2.0 resolution: "acorn-walk@npm:8.2.0" @@ -2736,7 +2943,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.12.0, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": +"acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.12.0, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": version: 8.12.1 resolution: "acorn@npm:8.12.1" bin: @@ -3415,6 +3622,8 @@ __metadata: connect-busboy: "npm:1.0.0" cors: "npm:2.8.5" emoji-name-map: "npm:1.2.9" + esbuild: "npm:0.23.1" + esbuild-plugin-tsc: "npm:0.4.0" eslint: "npm:8.57.0" eslint-config-prettier: "npm:9.1.0" eslint-module-utils: "npm:2.11.0" @@ -4058,6 +4267,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^7.2.0": + version: 7.2.0 + resolution: "commander@npm:7.2.0" + checksum: 10c0/8d690ff13b0356df7e0ebbe6c59b4712f754f4b724d4f473d3cc5b3fdcf978e3a5dc3078717858a2ceb50b0f84d0660a7f22a96cdc50fb877d0c9bb31593d23a + languageName: node + linkType: hard + "commander@npm:^8.3.0": version: 8.3.0 resolution: "commander@npm:8.3.0" @@ -4594,6 +4810,13 @@ __metadata: languageName: node linkType: hard +"debounce@npm:^1.2.1": + version: 1.2.1 + resolution: "debounce@npm:1.2.1" + checksum: 10c0/6c9320aa0973fc42050814621a7a8a78146c1975799b5b3cc1becf1f77ba9a5aa583987884230da0842a03f385def452fad5d60db97c3d1c8b824e38a8edf500 + languageName: node + linkType: hard + "debug@npm:2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -4991,6 +5214,13 @@ __metadata: languageName: node linkType: hard +"duplexer@npm:^0.1.2": + version: 0.1.2 + resolution: "duplexer@npm:0.1.2" + checksum: 10c0/c57bcd4bdf7e623abab2df43a7b5b23d18152154529d166c1e0da6bee341d84c432d157d7e97b32fecb1bf3a8b8857dd85ed81a915789f550637ed25b8e64fc2 + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -5394,6 +5624,111 @@ __metadata: languageName: node linkType: hard +"esbuild-plugin-compressor@npm:1.0.1": + version: 1.0.1 + resolution: "esbuild-plugin-compressor@npm:1.0.1" + dependencies: + fs-extra: "npm:^11.1.1" + peerDependencies: + esbuild: ^0.17.19 + checksum: 10c0/0d9b6e614af77217539874e40b7d5e049591a82f215c9a5ad8cba3c6c661560a6071abe7f37a5395017593c78e46308e1cfb87a01ffefbfd30f93307a4acdb75 + languageName: node + linkType: hard + +"esbuild-plugin-tsc@npm:0.4.0": + version: 0.4.0 + resolution: "esbuild-plugin-tsc@npm:0.4.0" + dependencies: + strip-comments: "npm:^2.0.1" + peerDependencies: + typescript: ^4.0.0 || ^5.0.0 + checksum: 10c0/80d80327b87c27c6054bea2d1236c1295420f05d392d6e7c3069e57f4359666bd005b70fb6cb44c2e5d0c3c4875c5c0358908f6a83e587a6025966977356bfff + languageName: node + linkType: hard + +"esbuild@npm:0.23.1": + version: 0.23.1 + resolution: "esbuild@npm:0.23.1" + dependencies: + "@esbuild/aix-ppc64": "npm:0.23.1" + "@esbuild/android-arm": "npm:0.23.1" + "@esbuild/android-arm64": "npm:0.23.1" + "@esbuild/android-x64": "npm:0.23.1" + "@esbuild/darwin-arm64": "npm:0.23.1" + "@esbuild/darwin-x64": "npm:0.23.1" + "@esbuild/freebsd-arm64": "npm:0.23.1" + "@esbuild/freebsd-x64": "npm:0.23.1" + "@esbuild/linux-arm": "npm:0.23.1" + "@esbuild/linux-arm64": "npm:0.23.1" + "@esbuild/linux-ia32": "npm:0.23.1" + "@esbuild/linux-loong64": "npm:0.23.1" + "@esbuild/linux-mips64el": "npm:0.23.1" + "@esbuild/linux-ppc64": "npm:0.23.1" + "@esbuild/linux-riscv64": "npm:0.23.1" + "@esbuild/linux-s390x": "npm:0.23.1" + "@esbuild/linux-x64": "npm:0.23.1" + "@esbuild/netbsd-x64": "npm:0.23.1" + "@esbuild/openbsd-arm64": "npm:0.23.1" + "@esbuild/openbsd-x64": "npm:0.23.1" + "@esbuild/sunos-x64": "npm:0.23.1" + "@esbuild/win32-arm64": "npm:0.23.1" + "@esbuild/win32-ia32": "npm:0.23.1" + "@esbuild/win32-x64": "npm:0.23.1" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/08c2ed1105cc3c5e3a24a771e35532fe6089dd24a39c10097899072cef4a99f20860e41e9294e000d86380f353b04d8c50af482483d7f69f5208481cce61eec7 + languageName: node + linkType: hard + "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" @@ -6306,7 +6641,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^11.1.0, fs-extra@npm:^11.2.0": +"fs-extra@npm:^11.1.0, fs-extra@npm:^11.1.1, fs-extra@npm:^11.2.0": version: 11.2.0 resolution: "fs-extra@npm:11.2.0" dependencies: @@ -6895,6 +7230,15 @@ __metadata: languageName: node linkType: hard +"gzip-size@npm:^6.0.0": + version: 6.0.0 + resolution: "gzip-size@npm:6.0.0" + dependencies: + duplexer: "npm:^0.1.2" + checksum: 10c0/4ccb924626c82125897a997d1c84f2377846a6ef57fbee38f7c0e6b41387fba4d00422274440747b58008b5d60114bac2349c2908e9aba55188345281af40a3f + languageName: node + linkType: hard + "handlebars@npm:^4.7.7": version: 4.7.7 resolution: "handlebars@npm:4.7.7" @@ -7039,7 +7383,7 @@ __metadata: languageName: node linkType: hard -"html-escaper@npm:^2.0.0": +"html-escaper@npm:^2.0.0, html-escaper@npm:^2.0.2": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" checksum: 10c0/208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 @@ -9445,6 +9789,13 @@ __metadata: languageName: node linkType: hard +"mrmime@npm:^2.0.0": + version: 2.0.0 + resolution: "mrmime@npm:2.0.0" + checksum: 10c0/312b35ed288986aec90955410b21ed7427fd1e4ee318cb5fc18765c8d029eeded9444faa46589e5b1ed6b35fb2054a802ac8dcb917ddf6b3e189cb3bf11a965c + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -10124,6 +10475,15 @@ __metadata: languageName: node linkType: hard +"opener@npm:^1.5.2": + version: 1.5.2 + resolution: "opener@npm:1.5.2" + bin: + opener: bin/opener-bin.js + checksum: 10c0/dd56256ab0cf796585617bc28e06e058adf09211781e70b264c76a1dbe16e90f868c974e5bf5309c93469157c7d14b89c35dc53fe7293b0e40b4d2f92073bc79 + languageName: node + linkType: hard + "optionator@npm:^0.9.3": version: 0.9.3 resolution: "optionator@npm:0.9.3" @@ -12080,6 +12440,17 @@ __metadata: languageName: node linkType: hard +"sirv@npm:^2.0.3": + version: 2.0.4 + resolution: "sirv@npm:2.0.4" + dependencies: + "@polka/url": "npm:^1.0.0-next.24" + mrmime: "npm:^2.0.0" + totalist: "npm:^3.0.0" + checksum: 10c0/68f8ee857f6a9415e9c07a1f31c7c561df8d5f1b1ba79bee3de583fa37da8718def5309f6b1c6e2c3ef77de45d74f5e49efc7959214443aa92d42e9c99180a4e + languageName: node + linkType: hard + "slash@npm:3.0.0, slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -12538,6 +12909,13 @@ __metadata: languageName: node linkType: hard +"strip-comments@npm:^2.0.1": + version: 2.0.1 + resolution: "strip-comments@npm:2.0.1" + checksum: 10c0/984321b1ec47a531bdcfddd87f217590934e2d2f142198a080ec88588280239a5b58a81ca780730679b6195e52afef83673c6d6466c07c2277f71f44d7d9553d + languageName: node + linkType: hard + "strip-final-newline@npm:^2.0.0": version: 2.0.0 resolution: "strip-final-newline@npm:2.0.0" @@ -12882,6 +13260,13 @@ __metadata: languageName: node linkType: hard +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 10c0/4bb1fadb69c3edbef91c73ebef9d25b33bbf69afe1e37ce544d5f7d13854cda15e47132f3e0dc4cafe300ddb8578c77c50a65004d8b6e97e77934a69aa924863 + languageName: node + linkType: hard + "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -13218,6 +13603,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:5.6.2": + version: 5.6.2 + resolution: "typescript@npm:5.6.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/3ed8297a8c7c56b7fec282532503d1ac795239d06e7c4966b42d4330c6cf433a170b53bcf93a130a7f14ccc5235de5560df4f1045eb7f3550b46ebed16d3c5e5 + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A5.5.4#optional!builtin, typescript@patch:typescript@npm%3A>=3 < 6#optional!builtin": version: 5.5.4 resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin::version=5.5.4&hash=379a07" @@ -13228,6 +13623,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A5.6.2#optional!builtin": + version: 5.6.2 + resolution: "typescript@patch:typescript@npm%3A5.6.2#optional!builtin::version=5.6.2&hash=8c6c40" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/94eb47e130d3edd964b76da85975601dcb3604b0c848a36f63ac448d0104e93819d94c8bdf6b07c00120f2ce9c05256b8b6092d23cf5cf1c6fa911159e4d572f + languageName: node + linkType: hard + "ua-parser-js@npm:^0.7.30": version: 0.7.33 resolution: "ua-parser-js@npm:0.7.33" @@ -13679,6 +14084,28 @@ __metadata: languageName: node linkType: hard +"webpack-bundle-analyzer@npm:4.10.2": + version: 4.10.2 + resolution: "webpack-bundle-analyzer@npm:4.10.2" + dependencies: + "@discoveryjs/json-ext": "npm:0.5.7" + acorn: "npm:^8.0.4" + acorn-walk: "npm:^8.0.0" + commander: "npm:^7.2.0" + debounce: "npm:^1.2.1" + escape-string-regexp: "npm:^4.0.0" + gzip-size: "npm:^6.0.0" + html-escaper: "npm:^2.0.2" + opener: "npm:^1.5.2" + picocolors: "npm:^1.0.0" + sirv: "npm:^2.0.3" + ws: "npm:^7.3.1" + bin: + webpack-bundle-analyzer: lib/bin/analyzer.js + checksum: 10c0/00603040e244ead15b2d92981f0559fa14216381349412a30070a7358eb3994cd61a8221d34a3b3fb8202dc3d1c5ee1fbbe94c5c52da536e5b410aa1cf279a48 + languageName: node + linkType: hard + "webpack-cli@npm:5.1.4": version: 5.1.4 resolution: "webpack-cli@npm:5.1.4" @@ -13756,7 +14183,7 @@ __metadata: languageName: node linkType: hard -"webpack@npm:5.94.0": +"webpack@npm:5.94.0, webpack@npm:^5": version: 5.94.0 resolution: "webpack@npm:5.94.0" dependencies: @@ -13996,6 +14423,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:^7.3.1": + version: 7.5.10 + resolution: "ws@npm:7.5.10" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/bd7d5f4aaf04fae7960c23dcb6c6375d525e00f795dd20b9385902bd008c40a94d3db3ce97d878acc7573df852056ca546328b27b39f47609f80fb22a0a9b61d + languageName: node + linkType: hard + "ws@npm:^8.14.2, ws@npm:^8.18.0, ws@npm:^8.8.0": version: 8.18.0 resolution: "ws@npm:8.18.0"