Skip to content

docs(changelog): Note Expo Router prefetch PII-gating behavior change

30484d2
Select commit
Loading
Failed to load commit list.
Merged

feat(tracing): Wrap Expo Router push, replace, navigate, back, dismiss in addition to prefetch #6221

docs(changelog): Note Expo Router prefetch PII-gating behavior change
30484d2
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden completed Jun 2, 2026 in 26m 31s

3 issues

Low

Test `'returns the router unchanged if prefetch method does not exist'` is stale after navigation method wrapping was added - `packages/core/test/tracing/expoRouter.test.ts:57`

The test at lines 51โ€“55 passes a { push: jest.fn() } router and asserts the router is "unchanged", but the new code now mutates router.push with a wrapped function and sets __sentryWrapped. The toBe (reference equality) assertion still passes, so the test silently no longer verifies its stated intent and could mask future regressions in navigation-method wrapping.

`ExpoRouterHref` used in public API but not exported from entry point - `packages/core/etc/sentry-react-native.api.md:278-281`

The prefetch signature now references ExpoRouterHref (a non-exported type) in the public ExpoRouter interface. TypeScript consumers who need to explicitly reference this parameter type can no longer do so โ€” they'd have to use a workaround like Parameters<NonNullable<ExpoRouter['prefetch']>>[0]. Export ExpoRouterHref from packages/core/src/js/tracing/index.ts to restore full API usability.

Stale `pendingExpoRouterNavigation` if a wrapped router call succeeds without triggering the React Navigation `__unsafe_action__` listener - `packages/core/src/js/tracing/expoRouter.ts:170-200`

wrapExpoRouter sets pendingExpoRouterNavigation before invoking the original router method and only clears it on the throw path. On the success path it relies on startIdleNavigationSpan (registered as the __unsafe_action__ listener on the navigation container) to call consumePendingExpoRouterNavigation(). If the wrapped call succeeds but the listener never fires for it โ€” for example because registerNavigationContainer has not been called yet, or the underlying router call is intercepted before reaching React Navigation's dispatch โ€” the module-level pending value persists and will be consumed (and incorrectly attributed) by the next unrelated navigation. Adding a finally-style clear (or ensuring drain after original.apply) would make the contract symmetric with the catch branch.

4 skills analyzed
Skill Findings Duration Cost
security-review 0 2m 2s $0.44
code-review 1 8m 40s $2.40
find-bugs 2 25m 56s $5.08
gha-security-review 0 17.5s $0.15

โฑ 36m 55s ยท 3.8M in / 265.2k out ยท $8.07