Skip to content

feat(tracing): Add extend app start API for standalone app start#6392

Open
antonis wants to merge 8 commits into
mainfrom
antonis/rn-675-add-api-to-extend-app-start-react-native
Open

feat(tracing): Add extend app start API for standalone app start#6392
antonis wants to merge 8 commits into
mainfrom
antonis/rn-675-add-api-to-extend-app-start-react-native

feat(tracing): Add extend app start API for standalone app start (RN-…

4620572
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden: code-review completed Jul 2, 2026

2 issues

code-review: Found 2 issues (1 medium, 1 low)

Medium

`finalizeStandaloneAppStart` loses the trimmed end time when `appStartEndData` is unset - `packages/core/etc/sentry-react-native.api.md:308`

When extendAppStart() is used in standalone mode without Sentry.wrap() or appLoaded(), appStartEndData is null at finalization time. The guard if (appStartEndData && trimmedEndMs) on line 857 of appStart.ts then skips the mutation that propagates trimmedEndMs into appStartEndData. As a result, attachAppStartToTransactionEvent falls back to getBundleStartTimestampMs() and overwrites event.timestamp with the bundle-start time, nullifying the extension and producing an incorrect (shorter) measurement and transaction end — defeating the purpose of the API for users who don't use wrap(). Note that the normal captureStandaloneAppStart path does self-heal by calling _setAppStartEndData, but the extend/finalize path has no equivalent, so it depends solely on wrap()/appLoaded() having run.

Also found at:

  • packages/core/src/js/tracing/integrations/appStart.ts:47

Low

runApplication reset during in-flight finalizeStandaloneAppStart poisons appStartDataFlushed for the next run - `packages/core/src/js/tracing/integrations/appStart.ts:406-407`

Resetting extendedAppStartFinalized = false (and appStartDataFlushed = false) synchronously in the runApplication handler while finalizeStandaloneAppStart is still awaiting NATIVE.fetchNativeAppStart() can cause the resumed finalization to re-set appStartDataFlushed = true against the new run's state, silently dropping the next run's app start capture. Consider checking a generation counter or snapshotting key state into the async closure before yielding.


⏱ 17m 1s · 2.5M in / 136.9k out · $4.56

Annotations

Check warning on line 308 in packages/core/etc/sentry-react-native.api.md

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

`finalizeStandaloneAppStart` loses the trimmed end time when `appStartEndData` is unset

When `extendAppStart()` is used in standalone mode without `Sentry.wrap()` or `appLoaded()`, `appStartEndData` is null at finalization time. The guard `if (appStartEndData && trimmedEndMs)` on line 857 of `appStart.ts` then skips the mutation that propagates `trimmedEndMs` into `appStartEndData`. As a result, `attachAppStartToTransactionEvent` falls back to `getBundleStartTimestampMs()` and overwrites `event.timestamp` with the bundle-start time, nullifying the extension and producing an incorrect (shorter) measurement and transaction end — defeating the purpose of the API for users who don't use `wrap()`. Note that the normal `captureStandaloneAppStart` path does self-heal by calling `_setAppStartEndData`, but the extend/finalize path has no equivalent, so it depends solely on `wrap()`/`appLoaded()` having run.

Check warning on line 47 in packages/core/src/js/tracing/integrations/appStart.ts

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[3S5-9QG] `finalizeStandaloneAppStart` loses the trimmed end time when `appStartEndData` is unset (additional location)

When `extendAppStart()` is used in standalone mode without `Sentry.wrap()` or `appLoaded()`, `appStartEndData` is null at finalization time. The guard `if (appStartEndData && trimmedEndMs)` on line 857 of `appStart.ts` then skips the mutation that propagates `trimmedEndMs` into `appStartEndData`. As a result, `attachAppStartToTransactionEvent` falls back to `getBundleStartTimestampMs()` and overwrites `event.timestamp` with the bundle-start time, nullifying the extension and producing an incorrect (shorter) measurement and transaction end — defeating the purpose of the API for users who don't use `wrap()`. Note that the normal `captureStandaloneAppStart` path does self-heal by calling `_setAppStartEndData`, but the extend/finalize path has no equivalent, so it depends solely on `wrap()`/`appLoaded()` having run.