import { monitor, noop, timeStampNow } from '@datadog/browser-core' import type { RumMutationRecord } from '@datadog/browser-rum-core' import { getMutationObserverConstructor } from '@datadog/browser-rum-core' import type { RecordingScope } from '../recordingScope' import { createMutationBatch } from '../mutationBatch' import type { EmitRecordCallback, EmitStatsCallback } from '../record.types' import { serializeMutationsAsChange } from '../serialization' import type { Tracker } from './tracker.types' export type MutationTracker = Tracker & { flush: () => void } /** * Buffers and aggregate mutations generated by a MutationObserver into MutationPayload */ export function trackMutation( target: Node, emitRecord: EmitRecordCallback, emitStats: EmitStatsCallback, scope: RecordingScope ): MutationTracker { const MutationObserver = getMutationObserverConstructor() if (!MutationObserver) { return { stop: noop, flush: noop } } const mutationBatch = createMutationBatch((mutations) => { serializeMutationsAsChange( timeStampNow(), mutations.concat(observer.takeRecords() as RumMutationRecord[]), emitRecord, emitStats, scope ) }) const observer = new MutationObserver(monitor(mutationBatch.addMutations)) observer.observe(target, { attributeOldValue: true, attributes: true, characterData: true, characterDataOldValue: true, childList: true, subtree: true, }) return { stop: () => { observer.disconnect() mutationBatch.stop() }, flush: () => { mutationBatch.flush() }, } }