Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/core-flag-called-react-native-version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@posthog/core': patch
---

Keep `$react_native_version` on minimal `$feature_flag_called` events
5 changes: 5 additions & 0 deletions .changeset/react-native-version-property.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'posthog-react-native': minor
---

Add `$react_native_version` (for example `0.79.6`) to events captured from JavaScript
2 changes: 2 additions & 0 deletions packages/core/src/featureFlagUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ export const MINIMAL_FLAG_CALLED_EVENT_PROPERTIES: readonly string[] = [
'$lib_version',
'$device_id',
'$is_server',
// Runtime identity, kept for runtime breakdowns of flag calls
'$react_native_version',
]

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3347,6 +3347,11 @@
"type": "string | null",
"name": "$os_version"
},
{
"description": "React Native version like \"0.79.6\"",
"type": "string | null",
"name": "$react_native_version"
},
{
"description": "Timezone of the device like \"Europe/Berlin\"",
"type": "string | null",
Expand Down
7 changes: 6 additions & 1 deletion packages/react-native/src/native-deps.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OptionalAsyncStorage } from './optional/OptionalAsyncStorage'
import { GLOBAL_OBJ, getPlatformOS, isMacOS, isWeb, isWindows } from './utils'
import { GLOBAL_OBJ, getPlatformOS, getReactNativeVersion, isMacOS, isWeb, isWindows } from './utils'
import { OptionalExpoApplication } from './optional/OptionalExpoApplication'
import { OptionalExpoDevice } from './optional/OptionalExpoDevice'
import { OptionalExpoFileSystem } from './optional/OptionalExpoFileSystem'
Expand Down Expand Up @@ -39,6 +39,11 @@ export const getAppProperties = (): PostHogCustomAppProperties => {
$device_type: currentDeviceType,
}

const reactNativeVersion = getReactNativeVersion()
if (reactNativeVersion) {
properties.$react_native_version = reactNativeVersion
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Resolved

if (OptionalExpoApplication) {
properties.$app_build = OptionalExpoApplication.nativeBuildVersion
properties.$app_name = OptionalExpoApplication.applicationName
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ export interface PostHogCustomAppProperties {
$timezone?: string | null
/** Whether the app is running on an emulator/simulator */
$is_emulator?: boolean | null
/** React Native version like "0.79.6" */
$react_native_version?: string | null
}

export type PostHogSessionReplayConfig = {
Expand Down
17 changes: 17 additions & 0 deletions packages/react-native/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,20 @@ export function isWindows(): boolean {
}

export const isHermes = () => !!GLOBAL_OBJ.HermesInternal

type ReactNativeVersion = { major: number; minor: number; patch: number; prerelease?: number | string | null }

/** React Native version like "0.79.6" or "0.80.0-rc.2", or undefined where Platform.constants doesn't report it (e.g. web) */
export function getReactNativeVersion(): string | undefined {
try {
const version = (Platform as { constants?: { reactNativeVersion?: ReactNativeVersion } }).constants
?.reactNativeVersion
if (!version || typeof version.major !== 'number') {
return undefined
}
const { major, minor, patch, prerelease } = version
return `${major}.${minor}.${patch}${prerelease != null ? `-${prerelease}` : ''}`
} catch {
return undefined
}
}
67 changes: 67 additions & 0 deletions packages/react-native/test/react-native-version.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Platform } from 'react-native'
import { minimizeFlagCalledEventProperties } from '@posthog/core'
import { PostHog } from '../src'
import { getReactNativeVersion } from '../src/utils'

const platform = Platform as typeof Platform & { constants?: unknown }

describe('$react_native_version', () => {
afterEach(() => {
delete platform.constants
})

it('formats Platform.constants.reactNativeVersion', () => {
platform.constants = { reactNativeVersion: { major: 0, minor: 79, patch: 6, prerelease: null } }
expect(getReactNativeVersion()).toBe('0.79.6')
})

it('appends the prerelease tag', () => {
platform.constants = { reactNativeVersion: { major: 0, minor: 80, patch: 0, prerelease: 'rc.2' } }
expect(getReactNativeVersion()).toBe('0.80.0-rc.2')
})

it('is undefined when the platform does not report a version', () => {
platform.constants = {}
expect(getReactNativeVersion()).toBeUndefined()
})

it('is undefined when the version object has no numeric fields', () => {
platform.constants = { reactNativeVersion: {} }
expect(getReactNativeVersion()).toBeUndefined()
})

it('is undefined when reading the constants throws', () => {
Object.defineProperty(platform, 'constants', {
configurable: true,
get: () => {
throw new Error('getConstants failed')
},
})
expect(getReactNativeVersion()).toBeUndefined()
})

it('is sent with every event', async () => {
platform.constants = { reactNativeVersion: { major: 0, minor: 79, patch: 6 } }
const posthog = new PostHog('test-token', { flushInterval: 0 })
await posthog.ready()

expect(posthog.getCommonEventProperties().$react_native_version).toBe('0.79.6')

await posthog.shutdown()
})

it('survives minimal $feature_flag_called events', () => {
expect(minimizeFlagCalledEventProperties({ $react_native_version: '0.79.6', custom: 'dropped' })).toEqual({
$react_native_version: '0.79.6',
})
})

it('is omitted when the platform does not report a version', async () => {
const posthog = new PostHog('test-token', { flushInterval: 0 })
await posthog.ready()

expect(posthog.getCommonEventProperties()).not.toHaveProperty('$react_native_version')

await posthog.shutdown()
})
})
Loading