var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { debug, getCapturedScopesOnSpan, getClient, getCurrentScope, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, spanIsSampled, startInactiveSpan, timestampInSeconds, } from '@sentry/core';
import { getAppRegistryIntegration } from '../../integrations/appRegistry';
import { APP_START_COLD as APP_START_COLD_MEASUREMENT, APP_START_WARM as APP_START_WARM_MEASUREMENT, } from '../../measurements';
import { convertSpanToTransaction, isRootSpan, setEndTimeValue } from '../../utils/span';
import { NATIVE } from '../../wrapper';
import { getRootSpanDiscardReason, getTransactionEventDiscardReason } from '../onSpanEndUtils';
import { APP_START_COLD as APP_START_COLD_OP, APP_START_WARM as APP_START_WARM_OP, UI_LOAD as UI_LOAD_OP, } from '../ops';
import { SPAN_ORIGIN_AUTO_APP_START, SPAN_ORIGIN_MANUAL_APP_START } from '../origin';
import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../semanticAttributes';
import { setMainThreadInfo } from '../span';
import { createChildSpanJSON, createSpanJSON, getBundleStartTimestampMs } from '../utils';
const INTEGRATION_NAME = 'AppStart';
/**
 * We filter out app start more than 60s.
 * This could be due to many different reasons.
 * We've seen app starts with hours, days and even months.
 */
const MAX_APP_START_DURATION_MS = 60000;
/** We filter out App starts which timestamp is 60s and more before the transaction start */
const MAX_APP_START_AGE_MS = 60000;
/** App Start transaction name */
const APP_START_TX_NAME = 'App Start';
let appStartEndData = undefined;
let isRecordedAppStartEndTimestampMsManual = false;
let isAppLoadedManuallyInvoked = false;
let rootComponentCreationTimestampMs = undefined;
let isRootComponentCreationTimestampMsManual = false;
/**
 * Records the application start end.
 * Used automatically by `Sentry.wrap` and `Sentry.ReactNativeProfiler`.
 *
 * @deprecated Use {@link appLoaded} from the public SDK API instead (`Sentry.appLoaded()`).
 */
export function captureAppStart() {
    return _captureAppStart({ isManual: true });
}
/**
 * Signals that the app has finished loading and is ready for user interaction.
 * Called internally by `appLoaded()` from the public SDK API.
 *
 * @private
 */
export function _appLoaded() {
    return __awaiter(this, void 0, void 0, function* () {
        if (isAppLoadedManuallyInvoked) {
            debug.warn('[AppStart] appLoaded() was already called. Subsequent calls are ignored.');
            return;
        }
        const client = getClient();
        if (!client) {
            debug.warn('[AppStart] appLoaded() was called before Sentry.init(). App start end will not be recorded.');
            return;
        }
        isAppLoadedManuallyInvoked = true;
        const timestampMs = timestampInSeconds() * 1000;
        // If auto-capture already ran (ReactNativeProfiler.componentDidMount), overwrite the timestamp.
        // The transaction hasn't been sent yet in non-standalone mode so this is safe.
        if (appStartEndData) {
            debug.log('[AppStart] appLoaded() overwriting auto-detected app start end timestamp.');
            appStartEndData.timestampMs = timestampMs;
            appStartEndData.endFrames = null;
        }
        else {
            _setAppStartEndData({ timestampMs, endFrames: null });
        }
        isRecordedAppStartEndTimestampMsManual = true;
        yield fetchAndUpdateEndFrames();
        const integration = client.getIntegrationByName(INTEGRATION_NAME);
        if (integration) {
            // Cancel any deferred standalone send from auto-capture — we'll send our own
            // with the correct manual timestamp instead of sending two transactions.
            integration.cancelDeferredStandaloneCapture();
            // In standalone mode, auto-capture may have already flushed the transaction.
            // Reset the flag so captureStandaloneAppStart can re-send with the manual timestamp.
            integration.resetAppStartDataFlushed();
            yield integration.captureStandaloneAppStart();
        }
    });
}
/**
 * For internal use only.
 *
 * @private
 */
export function _captureAppStart(_a) {
    return __awaiter(this, arguments, void 0, function* ({ isManual }) {
        // If appLoaded() was already called manually, skip the auto-capture to avoid
        // overwriting the manual end timestamp (race B: appLoaded before componentDidMount).
        if (!isManual && isAppLoadedManuallyInvoked) {
            debug.log('[AppStart] Skipping auto app start capture because appLoaded() was already called.');
            return;
        }
        const client = getClient();
        if (!client) {
            debug.warn('[AppStart] Could not capture App Start, missing client.');
            return;
        }
        isRecordedAppStartEndTimestampMsManual = isManual;
        const timestampMs = timestampInSeconds() * 1000;
        // Set end timestamp immediately to avoid race with processEvent
        // Frames data will be updated after the async fetch
        _setAppStartEndData({
            timestampMs,
            endFrames: null,
        });
        yield fetchAndUpdateEndFrames();
        const integration = client.getIntegrationByName(INTEGRATION_NAME);
        if (integration) {
            if (!isManual) {
                // For auto-capture, defer the standalone send to give appLoaded() a chance
                // to override the end timestamp before the transaction is sent.
                // If appLoaded() is called, it cancels this deferred send and sends its own.
                // In non-standalone mode, scheduleDeferredStandaloneCapture is a no-op.
                integration.scheduleDeferredStandaloneCapture();
            }
            else {
                yield integration.captureStandaloneAppStart();
            }
        }
    });
}
/**
 * Fetches native frames data and attaches it to the current app start end data.
 */
function fetchAndUpdateEndFrames() {
    return __awaiter(this, void 0, void 0, function* () {
        if (NATIVE.enableNative) {
            try {
                const endFrames = yield NATIVE.fetchNativeFrames();
                debug.log('[AppStart] Captured end frames for app start.', endFrames);
                _updateAppStartEndFrames(endFrames);
            }
            catch (error) {
                debug.log('[AppStart] Failed to capture end frames for app start.', error);
            }
        }
    });
}
/**
 * Sets the root component first constructor call timestamp.
 * Used automatically by `Sentry.wrap` and `Sentry.ReactNativeProfiler`.
 */
export function setRootComponentCreationTimestampMs(timestampMs) {
    (appStartEndData === null || appStartEndData === void 0 ? void 0 : appStartEndData.timestampMs) && debug.warn('Setting Root component creation timestamp after app start end is set.');
    rootComponentCreationTimestampMs && debug.warn('Overwriting already set root component creation timestamp.');
    rootComponentCreationTimestampMs = timestampMs;
    isRootComponentCreationTimestampMsManual = true;
}
/**
 * For internal use only.
 *
 * @private
 */
export function _setRootComponentCreationTimestampMs(timestampMs) {
    setRootComponentCreationTimestampMs(timestampMs);
    isRootComponentCreationTimestampMsManual = false;
}
/**
 * For internal use only.
 *
 * @private
 */
export const _setAppStartEndData = (data) => {
    appStartEndData && debug.warn('Overwriting already set app start end data.');
    appStartEndData = data;
};
/**
 * Updates only the endFrames on existing appStartEndData.
 * Used after the async fetchNativeFrames completes to attach frame data
 * without triggering the overwrite warning from _setAppStartEndData.
 *
 * @private
 */
export const _updateAppStartEndFrames = (endFrames) => {
    if (appStartEndData) {
        appStartEndData.endFrames = endFrames;
    }
};
/**
 * For testing purposes only.
 *
 * @private
 */
export function _clearRootComponentCreationTimestampMs() {
    rootComponentCreationTimestampMs = undefined;
}
/**
 * For testing purposes only.
 *
 * @private
 */
export function _clearAppStartEndData() {
    appStartEndData = undefined;
    isRecordedAppStartEndTimestampMsManual = false;
    isAppLoadedManuallyInvoked = false;
}
/**
 * Attaches frame data to a span's data object.
 */
function attachFrameDataToSpan(span, frames) {
    if (frames.totalFrames <= 0 && frames.slowFrames <= 0 && frames.frozenFrames <= 0) {
        debug.warn(`[AppStart] Detected zero slow or frozen frames. Not adding measurements to spanId (${span.span_id}).`);
        return;
    }
    span.data = span.data || {};
    span.data['frames.total'] = frames.totalFrames;
    span.data['frames.slow'] = frames.slowFrames;
    span.data['frames.frozen'] = frames.frozenFrames;
    debug.log('[AppStart] Attached frame data to span.', {
        spanId: span.span_id,
        frameData: {
            total: frames.totalFrames,
            slow: frames.slowFrames,
            frozen: frames.frozenFrames,
        },
    });
}
/**
 * Adds AppStart spans from the native layer to the transaction event.
 */
export const appStartIntegration = ({ standalone = false, } = {}) => {
    let _client = undefined;
    let isEnabled = true;
    let appStartDataFlushed = false;
    let afterAllSetupCalled = false;
    let firstStartedActiveRootSpanId = undefined;
    let firstStartedActiveRootSpan = undefined;
    let cachedNativeAppStart = undefined;
    let deferredStandaloneTimeout = undefined;
    const setup = (client) => {
        _client = client;
        const { enableAppStartTracking } = client.getOptions();
        if (!enableAppStartTracking) {
            isEnabled = false;
            debug.warn('[AppStart] App start tracking is disabled.');
        }
        client.on('spanStart', recordFirstStartedActiveRootSpanId);
    };
    const afterAllSetup = (client) => {
        var _a;
        if (afterAllSetupCalled) {
            return;
        }
        afterAllSetupCalled = true;
        // TODO: automatically set standalone based on the presence of the native layer navigation integration
        (_a = getAppRegistryIntegration(client)) === null || _a === void 0 ? void 0 : _a.onRunApplication(() => {
            if (appStartDataFlushed) {
                debug.log('[AppStartIntegration] Resetting app start data flushed flag based on runApplication call.');
                appStartDataFlushed = false;
                firstStartedActiveRootSpanId = undefined;
                firstStartedActiveRootSpan = undefined;
                isAppLoadedManuallyInvoked = false;
                cachedNativeAppStart = undefined;
                if (deferredStandaloneTimeout !== undefined) {
                    clearTimeout(deferredStandaloneTimeout);
                    deferredStandaloneTimeout = undefined;
                }
            }
            else {
                debug.log('[AppStartIntegration] Waiting for initial app start was flush, before updating based on runApplication call.');
            }
        });
    };
    const processEvent = (event) => __awaiter(void 0, void 0, void 0, function* () {
        if (!isEnabled || standalone) {
            return event;
        }
        if (event.type !== 'transaction') {
            // App start data is only relevant for transactions
            return event;
        }
        yield attachAppStartToTransactionEvent(event);
        return event;
    });
    const recordFirstStartedActiveRootSpanId = (rootSpan) => {
        if (firstStartedActiveRootSpanId) {
            // Check if the previously locked span was dropped after it ended (e.g., by
            // ignoreEmptyRouteChangeTransactions or ignoreEmptyBackNavigation marking
            // it for discard during spanEnd). If so, reset and allow this new span.
            // We check here (at the next spanStart) rather than at spanEnd because
            // the discard listeners run after the app start listener in registration order,
            // so the discard attribute is not yet set when our own spanEnd listener would fire.
            if (firstStartedActiveRootSpan && getRootSpanDiscardReason(firstStartedActiveRootSpan) !== undefined) {
                debug.log('[AppStart] Previously locked root span was marked for discard after ending. Resetting to allow next transaction.');
                resetFirstStartedActiveRootSpanId();
                // Fall through to lock to this new span
            }
            else {
                return;
            }
        }
        if (!isRootSpan(rootSpan)) {
            return;
        }
        if (!spanIsSampled(rootSpan)) {
            return;
        }
        firstStartedActiveRootSpan = rootSpan;
        setFirstStartedActiveRootSpanId(rootSpan.spanContext().spanId);
    };
    /**
     * Resets the first started active root span id and span reference to allow
     * the next root span's transaction to attempt app start attachment.
     */
    const resetFirstStartedActiveRootSpanId = () => {
        debug.log('[AppStart] Resetting first started active root span id to allow retry on next transaction.');
        firstStartedActiveRootSpanId = undefined;
        firstStartedActiveRootSpan = undefined;
    };
    /**
     * For testing purposes only.
     * @private
     */
    const setFirstStartedActiveRootSpanId = (spanId) => {
        firstStartedActiveRootSpanId = spanId;
        debug.log('[AppStart] First started active root span id recorded.', firstStartedActiveRootSpanId);
    };
    function captureStandaloneAppStart() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!_client) {
                // If client is not set, SDK was not initialized, logger is thus disabled
                // oxlint-disable-next-line eslint(no-console)
                console.warn('[AppStart] Could not capture App Start, missing client, call `Sentry.init` first.');
                return;
            }
            if (!standalone) {
                debug.log('[AppStart] App start tracking is enabled. App start will be added to the first transaction as a child span.');
                return;
            }
            debug.log('[AppStart] App start tracking standalone root span (transaction).');
            if (!(appStartEndData === null || appStartEndData === void 0 ? void 0 : appStartEndData.endFrames) && NATIVE.enableNative) {
                try {
                    const endFrames = yield NATIVE.fetchNativeFrames();
                    debug.log('[AppStart] Captured end frames for standalone app start.', endFrames);
                    const currentTimestamp = (appStartEndData === null || appStartEndData === void 0 ? void 0 : appStartEndData.timestampMs) || timestampInSeconds() * 1000;
                    _setAppStartEndData({
                        timestampMs: currentTimestamp,
                        endFrames,
                    });
                }
                catch (error) {
                    debug.log('[AppStart] Failed to capture frames for standalone app start.', error);
                }
            }
            const span = startInactiveSpan({
                forceTransaction: true,
                name: APP_START_TX_NAME,
                op: UI_LOAD_OP,
            });
            if (span instanceof SentryNonRecordingSpan) {
                // Tracing is disabled or the transaction was sampled
                return;
            }
            setEndTimeValue(span, timestampInSeconds());
            _client.emit('spanEnd', span);
            const event = convertSpanToTransaction(span);
            if (!event) {
                debug.warn('[AppStart] Failed to convert App Start span to transaction.');
                return;
            }
            yield attachAppStartToTransactionEvent(event);
            if (!event.spans || event.spans.length === 0) {
                // No spans were added to the transaction, so we don't need to send it
                return;
            }
            const scope = getCapturedScopesOnSpan(span).scope || getCurrentScope();
            scope.captureEvent(event);
        });
    }
    function attachAppStartToTransactionEvent(event) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            if (appStartDataFlushed) {
                // App start data is only relevant for the first transaction of the app run
                debug.log('[AppStart] App start data already flushed. Skipping.');
                return;
            }
            // Don't attach (and don't flip the flushed flag) for transactions the
            // tracing integration is about to drop — e.g. empty back-navigations,
            // route-change spans that never received route info, or childless idle
            // spans. Otherwise the next real transaction would be left without app
            // start data because `appStartDataFlushed` would already be `true`.
            if (getTransactionEventDiscardReason(event)) {
                debug.log('[AppStart] Skipping app start attach for transaction marked for discard.');
                return;
            }
            if (!((_a = event.contexts) === null || _a === void 0 ? void 0 : _a.trace)) {
                debug.warn('[AppStart] Transaction event is missing trace context. Can not attach app start.');
                return;
            }
            // When standalone is true, we create our own transaction and don't need to verify
            // it matches the first navigation transaction. When standalone is false, we need to
            // ensure we're attaching app start to the first transaction (not a later one).
            if (!standalone) {
                if (!firstStartedActiveRootSpanId) {
                    debug.warn('[AppStart] No first started active root span id recorded. Can not attach app start.');
                    return;
                }
                if (firstStartedActiveRootSpanId !== event.contexts.trace.span_id) {
                    debug.warn('[AppStart] First started active root span id does not match the transaction event span id. Can not attached app start.');
                    return;
                }
            }
            // All failure paths below set appStartDataFlushed = true to prevent
            // wasteful retries — these conditions won't change within the same app start.
            //
            // Use cached response if available (e.g. when _appLoaded() re-triggers
            // standalone capture after auto-capture already fetched from the native layer).
            // The native layer sets has_fetched = true after the first fetch, so a second
            // NATIVE.fetchNativeAppStart() call would incorrectly bail out.
            const isCached = cachedNativeAppStart !== undefined;
            const appStart = isCached ? cachedNativeAppStart : yield NATIVE.fetchNativeAppStart();
            cachedNativeAppStart = appStart;
            if (!appStart) {
                debug.warn('[AppStart] Failed to retrieve the app start metrics from the native layer.');
                appStartDataFlushed = true;
                return;
            }
            // Skip the has_fetched check when using a cached response — the native layer
            // sets has_fetched = true after the first fetch, but we intentionally re-use
            // the data when _appLoaded() overrides the app start end timestamp.
            if (!isCached && appStart.has_fetched) {
                debug.warn('[AppStart] Measured app start metrics were already reported from the native layer.');
                appStartDataFlushed = true;
                return;
            }
            const appStartTimestampMs = appStart.app_start_timestamp_ms;
            if (!appStartTimestampMs) {
                debug.warn('[AppStart] App start timestamp could not be loaded from the native layer.');
                appStartDataFlushed = true;
                return;
            }
            const appStartEndTimestampMs = (appStartEndData === null || appStartEndData === void 0 ? void 0 : appStartEndData.timestampMs) || getBundleStartTimestampMs();
            if (!appStartEndTimestampMs) {
                debug.warn('[AppStart] Javascript failed to record app start end. `_setAppStartEndData` was not called nor could the bundle start be found.');
                appStartDataFlushed = true;
                return;
            }
            const isAppStartWithinBounds = !!event.start_timestamp && appStartTimestampMs >= event.start_timestamp * 1000 - MAX_APP_START_AGE_MS;
            if (!__DEV__ && !isAppStartWithinBounds) {
                debug.warn('[AppStart] App start timestamp is too far in the past to be used for app start span.');
                appStartDataFlushed = true;
                return;
            }
            const appStartDurationMs = appStartEndTimestampMs - appStartTimestampMs;
            if (!__DEV__ && appStartDurationMs >= MAX_APP_START_DURATION_MS) {
                // Dev builds can have long app start waiting over minute for the first bundle to be produced
                debug.warn('[AppStart] App start duration is over a minute long, not adding app start span.');
                appStartDataFlushed = true;
                return;
            }
            if (appStartDurationMs < 0) {
                // This can happen when MainActivity on Android is recreated,
                // and the app start end timestamp is not updated, for example
                // due to missing `Sentry.wrap(RootComponent)` call.
                debug.warn('[AppStart] Last recorded app start end timestamp is before the app start timestamp.', 'This is usually caused by missing `Sentry.wrap(RootComponent)` call.');
                appStartDataFlushed = true;
                return;
            }
            appStartDataFlushed = true;
            event.contexts.trace.data = event.contexts.trace.data || {};
            event.contexts.trace.data[SEMANTIC_ATTRIBUTE_SENTRY_OP] = UI_LOAD_OP;
            event.contexts.trace.op = UI_LOAD_OP;
            const origin = isRecordedAppStartEndTimestampMsManual ? SPAN_ORIGIN_MANUAL_APP_START : SPAN_ORIGIN_AUTO_APP_START;
            event.contexts.trace.data[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = origin;
            event.contexts.trace.origin = origin;
            const appStartTimestampSeconds = appStartTimestampMs / 1000;
            event.start_timestamp = appStartTimestampSeconds;
            event.spans = event.spans || [];
            /** event.spans reference */
            const children = event.spans;
            const maybeTtidSpan = children.find(({ op }) => op === 'ui.load.initial_display');
            if (maybeTtidSpan) {
                maybeTtidSpan.start_timestamp = appStartTimestampSeconds;
                setSpanDurationAsMeasurementOnTransactionEvent(event, 'time_to_initial_display', maybeTtidSpan);
            }
            const maybeTtfdSpan = children.find(({ op }) => op === 'ui.load.full_display');
            if (maybeTtfdSpan) {
                maybeTtfdSpan.start_timestamp = appStartTimestampSeconds;
                setSpanDurationAsMeasurementOnTransactionEvent(event, 'time_to_full_display', maybeTtfdSpan);
            }
            const appStartEndTimestampSeconds = appStartEndTimestampMs / 1000;
            if (event.timestamp && event.timestamp < appStartEndTimestampSeconds) {
                debug.log('[AppStart] Transaction event timestamp is before app start end. Adjusting transaction event timestamp.');
                event.timestamp = appStartEndTimestampSeconds;
            }
            const op = appStart.type === 'cold' ? APP_START_COLD_OP : APP_START_WARM_OP;
            const appStartSpanJSON = createSpanJSON({
                op,
                description: appStart.type === 'cold' ? 'Cold Start' : 'Warm Start',
                start_timestamp: appStartTimestampSeconds,
                timestamp: appStartEndTimestampSeconds,
                trace_id: event.contexts.trace.trace_id,
                parent_span_id: event.contexts.trace.span_id,
                origin,
            });
            if (appStartEndData === null || appStartEndData === void 0 ? void 0 : appStartEndData.endFrames) {
                attachFrameDataToSpan(appStartSpanJSON, appStartEndData.endFrames);
                try {
                    const framesDelay = yield Promise.race([
                        NATIVE.fetchNativeFramesDelay(appStartTimestampSeconds, appStartEndTimestampSeconds),
                        new Promise(resolve => setTimeout(() => resolve(null), 2000)),
                    ]);
                    if (framesDelay != null) {
                        appStartSpanJSON.data = appStartSpanJSON.data || {};
                        appStartSpanJSON.data['frames.delay'] = framesDelay;
                    }
                }
                catch (error) {
                    debug.log('[AppStart] Error while fetching frames delay for app start span.', error);
                }
            }
            const jsExecutionSpanJSON = createJSExecutionStartSpan(appStartSpanJSON, rootComponentCreationTimestampMs);
            const appStartSpans = [
                appStartSpanJSON,
                ...(jsExecutionSpanJSON ? [jsExecutionSpanJSON] : []),
                ...convertNativeSpansToSpanJSON(appStartSpanJSON, appStart.spans),
            ];
            children.push(...appStartSpans);
            debug.log('[AppStart] Added app start spans to transaction event.', JSON.stringify(appStartSpans, undefined, 2));
            const measurementKey = appStart.type === 'cold' ? APP_START_COLD_MEASUREMENT : APP_START_WARM_MEASUREMENT;
            const measurementValue = {
                value: appStartDurationMs,
                unit: 'millisecond',
            };
            event.measurements = event.measurements || {};
            event.measurements[measurementKey] = measurementValue;
            debug.log('[AppStart] Added app start measurement to transaction event.', JSON.stringify(measurementValue, undefined, 2));
        });
    }
    const resetAppStartDataFlushed = () => {
        appStartDataFlushed = false;
    };
    const cancelDeferredStandaloneCapture = () => {
        if (deferredStandaloneTimeout !== undefined) {
            clearTimeout(deferredStandaloneTimeout);
            deferredStandaloneTimeout = undefined;
            debug.log('[AppStart] Cancelled deferred standalone app start capture.');
        }
    };
    const scheduleDeferredStandaloneCapture = () => {
        if (!standalone) {
            return;
        }
        deferredStandaloneTimeout = setTimeout(() => {
            deferredStandaloneTimeout = undefined;
            // oxlint-disable-next-line typescript-eslint(no-floating-promises)
            captureStandaloneAppStart();
        }, 0);
    };
    return {
        name: INTEGRATION_NAME,
        setup,
        afterAllSetup,
        processEvent,
        captureStandaloneAppStart,
        resetAppStartDataFlushed,
        cancelDeferredStandaloneCapture,
        scheduleDeferredStandaloneCapture,
        setFirstStartedActiveRootSpanId,
    };
};
function setSpanDurationAsMeasurementOnTransactionEvent(event, label, span) {
    if (!span.timestamp || !span.start_timestamp) {
        debug.warn('Span is missing start or end timestamp. Cam not set measurement on transaction event.');
        return;
    }
    event.measurements = event.measurements || {};
    event.measurements[label] = {
        value: (span.timestamp - span.start_timestamp) * 1000,
        unit: 'millisecond',
    };
}
/**
 * Adds JS Execution before React Root. If `Sentry.wrap` is not used, create a span for the start of JS Bundle execution.
 */
function createJSExecutionStartSpan(parentSpan, rootComponentCreationTimestampMs) {
    const bundleStartTimestampMs = getBundleStartTimestampMs();
    if (!bundleStartTimestampMs) {
        return undefined;
    }
    const bundleStartTimestampSeconds = bundleStartTimestampMs / 1000;
    if (bundleStartTimestampSeconds < parentSpan.start_timestamp) {
        debug.warn('Bundle start timestamp is before the app start span start timestamp. Skipping JS execution span.');
        return undefined;
    }
    if (!rootComponentCreationTimestampMs) {
        debug.warn('Missing the root component first constructor call timestamp.');
        return createChildSpanJSON(parentSpan, {
            description: 'JS Bundle Execution Start',
            start_timestamp: bundleStartTimestampSeconds,
            timestamp: bundleStartTimestampSeconds,
            origin: SPAN_ORIGIN_AUTO_APP_START,
        });
    }
    return createChildSpanJSON(parentSpan, {
        description: 'JS Bundle Execution Before React Root',
        start_timestamp: bundleStartTimestampSeconds,
        timestamp: rootComponentCreationTimestampMs / 1000,
        origin: isRootComponentCreationTimestampMsManual ? SPAN_ORIGIN_MANUAL_APP_START : SPAN_ORIGIN_AUTO_APP_START,
    });
}
/**
 * Adds native spans to the app start span.
 */
function convertNativeSpansToSpanJSON(parentSpan, nativeSpans) {
    return nativeSpans
        .filter(span => span.start_timestamp_ms / 1000 >= parentSpan.start_timestamp)
        .map(span => {
        if (span.description === 'UIKit init') {
            return setMainThreadInfo(createUIKitSpan(parentSpan, span));
        }
        return setMainThreadInfo(createChildSpanJSON(parentSpan, {
            description: span.description,
            start_timestamp: span.start_timestamp_ms / 1000,
            timestamp: span.end_timestamp_ms / 1000,
            origin: SPAN_ORIGIN_AUTO_APP_START,
        }));
    });
}
/**
 * UIKit init is measured by the native layers till the native SDK start
 * RN initializes the native SDK later, the end timestamp would be wrong
 */
function createUIKitSpan(parentSpan, nativeUIKitSpan) {
    const bundleStart = getBundleStartTimestampMs();
    // If UIKit init ends after the bundle start, the native SDK was auto-initialized
    // and so the end timestamp is incorrect.
    // The timestamps can't equal, as RN initializes after UIKit.
    if (bundleStart && bundleStart < nativeUIKitSpan.end_timestamp_ms) {
        return createChildSpanJSON(parentSpan, {
            description: 'UIKit Init to JS Exec Start',
            start_timestamp: nativeUIKitSpan.start_timestamp_ms / 1000,
            timestamp: bundleStart / 1000,
            origin: SPAN_ORIGIN_AUTO_APP_START,
        });
    }
    else {
        return createChildSpanJSON(parentSpan, {
            description: 'UIKit Init',
            start_timestamp: nativeUIKitSpan.start_timestamp_ms / 1000,
            timestamp: nativeUIKitSpan.end_timestamp_ms / 1000,
            origin: SPAN_ORIGIN_AUTO_APP_START,
        });
    }
}
//# sourceMappingURL=appStart.js.map