Skip to content

Commit

Permalink
feat: Add eventId overriding options (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite authored Jan 23, 2024
1 parent 91b1a21 commit 7000825
Show file tree
Hide file tree
Showing 16 changed files with 110 additions and 46 deletions.
23 changes: 12 additions & 11 deletions posthog-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
PosthogCoreOptions,
PostHogEventProperties,
PostHogPersistedProperty,
PosthogCaptureOptions,
PostHogCaptureOptions,
JsonType,
} from './types'
import {
Expand Down Expand Up @@ -155,7 +155,7 @@ export abstract class PostHogCoreStateless {
protected identifyStateless(
distinctId: string,
properties?: PostHogEventProperties,
options?: PosthogCaptureOptions
options?: PostHogCaptureOptions
): this {
// The properties passed to identifyStateless are event properties.
// To add person properties, pass in all person properties to the `$set` key.
Expand All @@ -176,7 +176,7 @@ export abstract class PostHogCoreStateless {
distinctId: string,
event: string,
properties?: { [key: string]: any },
options?: PosthogCaptureOptions
options?: PostHogCaptureOptions
): this {
const payload = this.buildPayload({ distinct_id: distinctId, event, properties })
this.enqueue('capture', payload, options)
Expand All @@ -188,7 +188,7 @@ export abstract class PostHogCoreStateless {
alias: string,
distinctId: string,
properties?: { [key: string]: any },
options?: PosthogCaptureOptions
options?: PostHogCaptureOptions
): this {
const payload = this.buildPayload({
event: '$create_alias',
Expand All @@ -211,7 +211,7 @@ export abstract class PostHogCoreStateless {
groupType: string,
groupKey: string | number,
groupProperties?: PostHogEventProperties,
options?: PosthogCaptureOptions,
options?: PostHogCaptureOptions,
distinctId?: string,
eventProperties?: PostHogEventProperties
): this {
Expand Down Expand Up @@ -402,7 +402,7 @@ export abstract class PostHogCoreStateless {
/***
*** QUEUEING AND FLUSHING
***/
protected enqueue(type: string, _message: any, options?: PosthogCaptureOptions): void {
protected enqueue(type: string, _message: any, options?: PostHogCaptureOptions): void {
if (this.optedOut) {
this._events.emit(type, `Library is disabled. Not sending event. To re-enable, call posthog.optIn()`)
return
Expand All @@ -414,6 +414,7 @@ export abstract class PostHogCoreStateless {
library: this.getLibraryId(),
library_version: this.getLibraryVersion(),
timestamp: options?.timestamp ? options?.timestamp : currentISOTime(),
uuid: options?.uuid ? options.uuid : generateUUID(globalThis),
}

const addGeoipDisableProperty = options?.disableGeoip ?? this.disableGeoip
Expand Down Expand Up @@ -747,7 +748,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
/***
*** TRACKING
***/
identify(distinctId?: string, properties?: PostHogEventProperties, options?: PosthogCaptureOptions): this {
identify(distinctId?: string, properties?: PostHogEventProperties, options?: PostHogCaptureOptions): this {
const previousDistinctId = this.getDistinctId()
distinctId = distinctId || previousDistinctId

Expand All @@ -774,7 +775,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
return this
}

capture(event: string, properties?: { [key: string]: any }, options?: PosthogCaptureOptions): this {
capture(event: string, properties?: { [key: string]: any }, options?: PostHogCaptureOptions): this {
const distinctId = this.getDistinctId()

if (properties?.$groups) {
Expand All @@ -801,7 +802,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
eventType: string,
elements: PostHogAutocaptureElement[],
properties: PostHogEventProperties = {},
options?: PosthogCaptureOptions
options?: PostHogCaptureOptions
): this {
const distinctId = this.getDistinctId()
const payload = {
Expand Down Expand Up @@ -844,7 +845,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
groupType: string,
groupKey: string | number,
groupProperties?: PostHogEventProperties,
options?: PosthogCaptureOptions
options?: PostHogCaptureOptions
): this {
this.groups({
[groupType]: groupKey,
Expand All @@ -861,7 +862,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
groupType: string,
groupKey: string | number,
groupProperties?: PostHogEventProperties,
options?: PosthogCaptureOptions
options?: PostHogCaptureOptions
): this {
const distinctId = this.getDistinctId()

Expand Down
5 changes: 4 additions & 1 deletion posthog-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ export type PostHogFetchOptions = {
}

// Check out posthog-js for these additional options and try to keep them in sync
export type PosthogCaptureOptions = {
export type PostHogCaptureOptions = {
/** If provided overrides the auto-generated event ID */
uuid?: string
/** If provided overrides the auto-generated timestamp */
timestamp?: Date
disableGeoip?: boolean
}
Expand Down
35 changes: 23 additions & 12 deletions posthog-core/test/posthog.capture.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { parseBody } from './test-utils/test-utils'
import { createTestClient, PostHogCoreTestClient, PostHogCoreTestClientMocks } from './test-utils/PostHogCoreTestClient'
import { generateUUID } from '../src/utils'

describe('PostHog Core', () => {
let posthog: PostHogCoreTestClient
Expand Down Expand Up @@ -37,35 +38,45 @@ describe('PostHog Core', () => {
$session_id: expect.any(String),
},
timestamp: '2022-01-01T00:00:00.000Z',
uuid: expect.any(String),
type: 'capture',
},
],
sent_at: '2022-01-01T00:00:00.000Z',
})
})

it('should allow overridding the timestamp', async () => {
it('should allow overriding the timestamp', async () => {
jest.setSystemTime(new Date('2022-01-01'))

posthog.capture('custom-event', { foo: 'bar' }, { timestamp: new Date('2021-01-02') })
const body = parseBody(mocks.fetch.mock.calls[0])

expect(body).toEqual({
expect(body).toMatchObject({
api_key: 'TEST_API_KEY',
batch: [
{
event: 'custom-event',
distinct_id: posthog.getDistinctId(),
library: 'posthog-core-tests',
library_version: '2.0.0-alpha',
properties: {
$lib: 'posthog-core-tests',
$lib_version: '2.0.0-alpha',
$session_id: expect.any(String),
foo: 'bar',
},
timestamp: '2021-01-02T00:00:00.000Z',
type: 'capture',
},
],
sent_at: '2022-01-01T00:00:00.000Z',
})
})

it('should allow overriding the uuid', async () => {
jest.setSystemTime(new Date('2022-01-01'))

const id = generateUUID()

posthog.capture('custom-event', { foo: 'bar' }, { uuid: id })
const body = parseBody(mocks.fetch.mock.calls[0])

expect(body).toMatchObject({
batch: [
{
event: 'custom-event',
uuid: expect.any(String),
},
],
sent_at: '2022-01-01T00:00:00.000Z',
Expand Down
1 change: 1 addition & 0 deletions posthog-core/test/posthog.identify.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ describe('PostHog Core', () => {
},
},
timestamp: '2022-01-01T00:00:00.000Z',
uuid: expect.any(String),
type: 'identify',
},
],
Expand Down
4 changes: 4 additions & 0 deletions posthog-node/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 3.6.0 - 2024-01-18

1. Adds support for overriding the event `uuid`

# 3.5.0 - 2024-01-09

1. When local evaluation is enabled, we automatically add flag information to all events sent to PostHog, whenever possible. This makes it easier to use these events in experiments.
Expand Down
2 changes: 1 addition & 1 deletion posthog-node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "posthog-node",
"version": "3.5.0",
"version": "3.6.0",
"description": "PostHog Node.js integration",
"repository": {
"type": "git",
Expand Down
19 changes: 14 additions & 5 deletions posthog-node/src/posthog-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
PostHogPersistedProperty,
} from '../../posthog-core/src'
import { PostHogMemoryStorage } from '../../posthog-core/src/storage-memory'
import { EventMessageV1, GroupIdentifyMessage, IdentifyMessageV1, PostHogNodeV1 } from './types'
import { EventMessage, GroupIdentifyMessage, IdentifyMessage, PostHogNodeV1 } from './types'
import { FeatureFlagsPoller } from './feature-flags'
import fetch from './fetch'

Expand Down Expand Up @@ -100,9 +100,18 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
this.featureFlagsPoller?.debug(enabled)
}

capture({ distinctId, event, properties, groups, sendFeatureFlags, timestamp, disableGeoip }: EventMessageV1): void {
const _capture = (props: EventMessageV1['properties']): void => {
super.captureStateless(distinctId, event, props, { timestamp, disableGeoip })
capture({
distinctId,
event,
properties,
groups,
sendFeatureFlags,
timestamp,
disableGeoip,
uuid,
}: EventMessage): void {
const _capture = (props: EventMessage['properties']): void => {
super.captureStateless(distinctId, event, props, { timestamp, disableGeoip, uuid })
}

// :TRICKY: If we flush, or need to shut down, to not lose events we want this promise to resolve before we flush
Expand Down Expand Up @@ -155,7 +164,7 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
this.addPendingPromise(capturePromise)
}

identify({ distinctId, properties, disableGeoip }: IdentifyMessageV1): void {
identify({ distinctId, properties, disableGeoip }: IdentifyMessage): void {
// Catch properties passed as $set and move them to the top level
const personProperties = properties?.$set || properties

Expand Down
9 changes: 5 additions & 4 deletions posthog-node/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { JsonType } from '../../posthog-core/src'

export interface IdentifyMessageV1 {
export interface IdentifyMessage {
distinctId: string
properties?: Record<string | number, any>
disableGeoip?: boolean
}

export interface EventMessageV1 extends IdentifyMessageV1 {
export interface EventMessage extends IdentifyMessage {
event: string
groups?: Record<string, string | number> // Mapping of group type to group id
sendFeatureFlags?: boolean
timestamp?: Date
uuid?: string
}

export interface GroupIdentifyMessage {
Expand Down Expand Up @@ -75,7 +76,7 @@ export type PostHogNodeV1 = {
* @param groups OPTIONAL | object of what groups are related to this event, example: { company: 'id:5' }. Can be used to analyze companies instead of users.
* @param sendFeatureFlags OPTIONAL | Used with experiments. Determines whether to send feature flag values with the event.
*/
capture({ distinctId, event, properties, groups, sendFeatureFlags }: EventMessageV1): void
capture({ distinctId, event, properties, groups, sendFeatureFlags }: EventMessage): void

/**
* @description Identify lets you add metadata on your users so you can more easily identify who they are in PostHog,
Expand All @@ -84,7 +85,7 @@ export type PostHogNodeV1 = {
* @param distinctId which uniquely identifies your user
* @param properties with a dict with any key: value pairs
*/
identify({ distinctId, properties }: IdentifyMessageV1): void
identify({ distinctId, properties }: IdentifyMessage): void

/**
* @description To marry up whatever a user does before they sign up or log in with what they do after you need to make an alias call.
Expand Down
1 change: 1 addition & 0 deletions posthog-node/test/extensions/sentry-integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ describe('PostHogSentryIntegration', () => {
library: 'posthog-node',
library_version: '1.2.3',
timestamp: expect.any(String),
uuid: expect.any(String),
},
])
})
Expand Down
20 changes: 20 additions & 0 deletions posthog-node/test/posthog-node.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ jest.mock('../src/fetch')
import fetch from '../src/fetch'
import { anyDecideCall, anyLocalEvalCall, apiImplementation } from './feature-flags.spec'
import { waitForPromises, wait } from '../../posthog-core/test/test-utils/test-utils'
import { generateUUID } from 'posthog-core/src/utils'

jest.mock('../package.json', () => ({ version: '1.2.3' }))

Expand Down Expand Up @@ -66,6 +67,7 @@ describe('PostHog Node.js', () => {
$lib: 'posthog-node',
$lib_version: '1.2.3',
},
uuid: expect.any(String),
timestamp: expect.any(String),
type: 'capture',
library: 'posthog-node',
Expand Down Expand Up @@ -185,6 +187,24 @@ describe('PostHog Node.js', () => {
distinct_id: '123',
timestamp: '2021-02-03T00:00:00.000Z',
event: 'custom-time',
uuid: expect.any(String),
},
])
})

it('should allow overriding uuid', async () => {
expect(mockedFetch).toHaveBeenCalledTimes(0)
const uuid = generateUUID()
posthog.capture({ event: 'custom-time', distinctId: '123', uuid })
await waitForPromises()
jest.runOnlyPendingTimers()
const batchEvents = getLastBatchEvents()
expect(batchEvents).toMatchObject([
{
distinct_id: '123',
timestamp: expect.any(String),
event: 'custom-time',
uuid: uuid,
},
])
})
Expand Down
4 changes: 4 additions & 0 deletions posthog-react-native/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 2.11.0 - 2024-01-23

1. Adds support for overriding the event `uuid` via capture options

# 2.10.2 - 2024-01-22

1. Do not try to load the `expo-file-system` package on the Web target since it's not supported.
Expand Down
6 changes: 3 additions & 3 deletions posthog-react-native/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "posthog-react-native",
"version": "2.10.2",
"version": "2.11.0",
"main": "lib/posthog-react-native/index.js",
"files": [
"lib/"
],
"repository": {
"type" : "git",
"url" : "https://github.com/PostHog/posthog-js-lite.git",
"type": "git",
"url": "https://github.com/PostHog/posthog-js-lite.git",
"directory": "posthog-react-native"
},
"scripts": {
Expand Down
15 changes: 10 additions & 5 deletions posthog-react-native/src/posthog-rn.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AppState, Dimensions, Linking } from 'react-native'

import {
PostHogCaptureOptions,
PostHogCore,
PosthogCoreOptions,
PostHogFetchOptions,
Expand Down Expand Up @@ -170,16 +171,20 @@ export class PostHog extends PostHogCore {
}

// Custom methods
screen(name: string, properties?: any): this {
screen(name: string, properties?: { [key: string]: any }, options?: PostHogCaptureOptions): this {
// Screen name is good to know for all other subsequent events
this.registerForSession({
$screen_name: name,
})

return this.capture('$screen', {
...properties,
$screen_name: name,
})
return this.capture(
'$screen',
{
...properties,
$screen_name: name,
},
options
)
}

initReactNativeNavigation(options: PostHogAutocaptureOptions): boolean {
Expand Down
Loading

0 comments on commit 7000825

Please sign in to comment.