import { datadogRum } from '@datadog/browser-rum'; import { buildAllowedTracingUrls } from './build-allowed-tracing-urls'; import { buildBeforeSend } from './build-before-send'; import { DATADOG_RUM_FOR_DEV, installDevConsole, isForceEnabled } from './runtime-override'; import type { SharedImpl } from './shared-impl'; import type { ApplicationConfig, ServiceConfig, State } from './types'; const DEFAULTS = { sessionSampleRate: 100, sessionReplaySampleRate: 0, defaultPrivacyLevel: 'mask-user-input', } as const; /** * Interop surface: stored on globalThis, shared across independently * deployed bundles. First bundle to load wins. Append-only — never * remove or change method signatures. */ export function createImpl(): SharedImpl { let initialized = false; const state: State = { services: new Map(), }; function initializeSdk( service: ServiceConfig, application: ApplicationConfig, enabled: boolean ): boolean { if (initialized) { // eslint-disable-next-line no-console console.info( '[datadog-rum] init: application config ignored; SDK already initialized.' ); return false; } if (datadogRum.getInitConfiguration()) { // eslint-disable-next-line no-console console.warn( '[datadog-rum] init: SDK was initialized outside the facade; service handlers will not fire.' ); return false; } const { beforeSend: appBeforeSend, ...sdkConfigPart } = application; if (appBeforeSend) { state.applicationBeforeSend = appBeforeSend; } datadogRum.init({ ...DEFAULTS, ...sdkConfigPart, service: service.name, beforeSend: buildBeforeSend(state), allowedTracingUrls: buildAllowedTracingUrls(state), }); if (!enabled) { datadogRum.setGlobalContextProperty(DATADOG_RUM_FOR_DEV, true); } initialized = true; return true; } function registerService({ name, ...reg }: ServiceConfig): void { const existing = state.services.get(name); state.services.set(name, { ...reg, context: existing?.context }); } return { init({ service, application, enabled = true }) { let initializedSdk = false; if (application) { if (!enabled) { installDevConsole(); } if (enabled || isForceEnabled()) { initializedSdk = initializeSdk(service, application, enabled); } } registerService(service); return { cleanup: () => state.services.delete(service.name), initializedSdk, }; }, setServiceContext(key, context) { const existing = state.services.get(key); state.services.set(key, { ...existing, context }); }, }; }