@posthog/core 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/error-tracking/chunk-ids.js +1 -1
- package/dist/error-tracking/chunk-ids.mjs +1 -1
- package/dist/error-tracking/coercers/error-event-coercer.js +4 -5
- package/dist/error-tracking/coercers/error-event-coercer.mjs +4 -5
- package/dist/error-tracking/coercers/event-coercer.js +1 -2
- package/dist/error-tracking/coercers/event-coercer.mjs +1 -2
- package/dist/error-tracking/coercers/object-coercer.js +1 -2
- package/dist/error-tracking/coercers/object-coercer.mjs +1 -2
- package/dist/error-tracking/coercers/primitive-coercer.js +1 -2
- package/dist/error-tracking/coercers/primitive-coercer.mjs +1 -2
- package/dist/error-tracking/coercers/promise-rejection-event.js +4 -5
- package/dist/error-tracking/coercers/promise-rejection-event.mjs +4 -5
- package/dist/error-tracking/coercers/string-coercer.js +3 -4
- package/dist/error-tracking/coercers/string-coercer.mjs +3 -4
- package/dist/error-tracking/coercers/utils.js +2 -4
- package/dist/error-tracking/coercers/utils.mjs +2 -4
- package/dist/error-tracking/error-properties-builder.d.ts +6 -6
- package/dist/error-tracking/error-properties-builder.d.ts.map +1 -1
- package/dist/error-tracking/error-properties-builder.js +17 -27
- package/dist/error-tracking/error-properties-builder.mjs +16 -26
- package/dist/error-tracking/parsers/index.js +2 -4
- package/dist/error-tracking/parsers/index.mjs +2 -4
- package/dist/error-tracking/parsers/node.js +3 -5
- package/dist/error-tracking/parsers/node.mjs +3 -5
- package/dist/error-tracking/utils.js +4 -4
- package/dist/error-tracking/utils.mjs +4 -4
- package/dist/eventemitter.js +4 -4
- package/dist/eventemitter.mjs +4 -4
- package/dist/featureFlagUtils.js +20 -45
- package/dist/featureFlagUtils.mjs +20 -45
- package/dist/gzip.js +1 -2
- package/dist/gzip.mjs +1 -2
- package/dist/index.d.ts +4 -366
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -1225
- package/dist/index.mjs +5 -1190
- package/dist/posthog-core-stateless.d.ts +204 -0
- package/dist/posthog-core-stateless.d.ts.map +1 -0
- package/dist/posthog-core-stateless.js +675 -0
- package/dist/posthog-core-stateless.mjs +632 -0
- package/dist/posthog-core.d.ts +171 -0
- package/dist/posthog-core.d.ts.map +1 -0
- package/dist/posthog-core.js +554 -0
- package/dist/posthog-core.mjs +520 -0
- package/dist/testing/PostHogCoreTestClient.d.ts +2 -1
- package/dist/testing/PostHogCoreTestClient.d.ts.map +1 -1
- package/dist/testing/PostHogCoreTestClient.js +9 -11
- package/dist/testing/PostHogCoreTestClient.mjs +8 -10
- package/dist/testing/test-utils.js +1 -1
- package/dist/testing/test-utils.mjs +1 -1
- package/dist/utils/bucketed-rate-limiter.js +8 -12
- package/dist/utils/bucketed-rate-limiter.mjs +8 -12
- package/dist/utils/index.js +3 -3
- package/dist/utils/index.mjs +3 -3
- package/dist/utils/type-utils.js +1 -1
- package/dist/utils/type-utils.mjs +1 -1
- package/dist/vendor/uuidv7.js +12 -16
- package/dist/vendor/uuidv7.mjs +12 -16
- package/package.json +3 -2
- package/src/__tests__/featureFlagUtils.spec.ts +427 -0
- package/src/__tests__/gzip.spec.ts +69 -0
- package/src/__tests__/posthog.ai.spec.ts +110 -0
- package/src/__tests__/posthog.capture.spec.ts +91 -0
- package/src/__tests__/posthog.core.spec.ts +135 -0
- package/src/__tests__/posthog.debug.spec.ts +36 -0
- package/src/__tests__/posthog.enqueue.spec.ts +93 -0
- package/src/__tests__/posthog.featureflags.spec.ts +1106 -0
- package/src/__tests__/posthog.featureflags.v1.spec.ts +922 -0
- package/src/__tests__/posthog.flush.spec.ts +237 -0
- package/src/__tests__/posthog.gdpr.spec.ts +50 -0
- package/src/__tests__/posthog.groups.spec.ts +96 -0
- package/src/__tests__/posthog.identify.spec.ts +194 -0
- package/src/__tests__/posthog.init.spec.ts +110 -0
- package/src/__tests__/posthog.listeners.spec.ts +51 -0
- package/src/__tests__/posthog.register.spec.ts +47 -0
- package/src/__tests__/posthog.reset.spec.ts +76 -0
- package/src/__tests__/posthog.sessions.spec.ts +63 -0
- package/src/__tests__/posthog.setProperties.spec.ts +102 -0
- package/src/__tests__/posthog.shutdown.spec.ts +88 -0
- package/src/__tests__/utils.spec.ts +36 -0
- package/src/error-tracking/chunk-ids.ts +58 -0
- package/src/error-tracking/coercers/dom-exception-coercer.ts +38 -0
- package/src/error-tracking/coercers/error-coercer.ts +36 -0
- package/src/error-tracking/coercers/error-event-coercer.ts +24 -0
- package/src/error-tracking/coercers/event-coercer.ts +19 -0
- package/src/error-tracking/coercers/index.ts +8 -0
- package/src/error-tracking/coercers/object-coercer.ts +76 -0
- package/src/error-tracking/coercers/primitive-coercer.ts +19 -0
- package/src/error-tracking/coercers/promise-rejection-event.spec.ts +77 -0
- package/src/error-tracking/coercers/promise-rejection-event.ts +53 -0
- package/src/error-tracking/coercers/string-coercer.spec.ts +26 -0
- package/src/error-tracking/coercers/string-coercer.ts +31 -0
- package/src/error-tracking/coercers/utils.ts +33 -0
- package/src/error-tracking/error-properties-builder.coerce.spec.ts +202 -0
- package/src/error-tracking/error-properties-builder.parse.spec.ts +30 -0
- package/src/error-tracking/error-properties-builder.ts +167 -0
- package/src/error-tracking/index.ts +5 -0
- package/src/error-tracking/parsers/base.ts +29 -0
- package/src/error-tracking/parsers/chrome.ts +53 -0
- package/src/error-tracking/parsers/gecko.ts +38 -0
- package/src/error-tracking/parsers/index.ts +104 -0
- package/src/error-tracking/parsers/node.ts +111 -0
- package/src/error-tracking/parsers/opera.ts +18 -0
- package/src/error-tracking/parsers/react-native.ts +0 -0
- package/src/error-tracking/parsers/safari.ts +33 -0
- package/src/error-tracking/parsers/winjs.ts +12 -0
- package/src/error-tracking/types.ts +107 -0
- package/src/error-tracking/utils.ts +39 -0
- package/src/eventemitter.ts +27 -0
- package/src/featureFlagUtils.ts +192 -0
- package/src/gzip.ts +29 -0
- package/src/index.ts +8 -0
- package/src/posthog-core-stateless.ts +1226 -0
- package/src/posthog-core.ts +958 -0
- package/src/testing/PostHogCoreTestClient.ts +91 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/test-utils.ts +47 -0
- package/src/types.ts +544 -0
- package/src/utils/bucketed-rate-limiter.spec.ts +33 -0
- package/src/utils/bucketed-rate-limiter.ts +85 -0
- package/src/utils/index.ts +98 -0
- package/src/utils/number-utils.spec.ts +89 -0
- package/src/utils/number-utils.ts +30 -0
- package/src/utils/promise-queue.spec.ts +55 -0
- package/src/utils/promise-queue.ts +30 -0
- package/src/utils/string-utils.ts +23 -0
- package/src/utils/type-utils.ts +134 -0
- package/src/vendor/uuidv7.ts +479 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { PostHogCore } from '@/posthog-core'
|
|
2
|
+
import type {
|
|
3
|
+
JsonType,
|
|
4
|
+
PostHogCoreOptions,
|
|
5
|
+
PostHogFetchOptions,
|
|
6
|
+
PostHogFetchResponse,
|
|
7
|
+
PostHogFlagsResponse,
|
|
8
|
+
} from '@/types'
|
|
9
|
+
|
|
10
|
+
const version = '2.0.0-alpha'
|
|
11
|
+
|
|
12
|
+
export interface PostHogCoreTestClientMocks {
|
|
13
|
+
fetch: jest.Mock<Promise<PostHogFetchResponse>, [string, PostHogFetchOptions]>
|
|
14
|
+
storage: {
|
|
15
|
+
getItem: jest.Mock<any | undefined, [string]>
|
|
16
|
+
setItem: jest.Mock<void, [string, any | null]>
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class PostHogCoreTestClient extends PostHogCore {
|
|
21
|
+
public _cachedDistinctId?: string
|
|
22
|
+
|
|
23
|
+
constructor(
|
|
24
|
+
private mocks: PostHogCoreTestClientMocks,
|
|
25
|
+
apiKey: string,
|
|
26
|
+
options?: PostHogCoreOptions
|
|
27
|
+
) {
|
|
28
|
+
super(apiKey, options)
|
|
29
|
+
|
|
30
|
+
this.setupBootstrap(options)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Expose protected methods for testing
|
|
34
|
+
public getFlags(
|
|
35
|
+
distinctId: string,
|
|
36
|
+
groups: Record<string, string | number> = {},
|
|
37
|
+
personProperties: Record<string, string> = {},
|
|
38
|
+
groupProperties: Record<string, Record<string, string>> = {},
|
|
39
|
+
extraPayload: Record<string, any> = {}
|
|
40
|
+
): Promise<PostHogFlagsResponse | undefined> {
|
|
41
|
+
return super.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getPersistedProperty<T>(key: string): T {
|
|
45
|
+
return this.mocks.storage.getItem(key)
|
|
46
|
+
}
|
|
47
|
+
setPersistedProperty<T>(key: string, value: T | null): void {
|
|
48
|
+
return this.mocks.storage.setItem(key, value)
|
|
49
|
+
}
|
|
50
|
+
fetch(url: string, options: PostHogFetchOptions): Promise<PostHogFetchResponse> {
|
|
51
|
+
return this.mocks.fetch(url, options)
|
|
52
|
+
}
|
|
53
|
+
getLibraryId(): string {
|
|
54
|
+
return 'posthog-core-tests'
|
|
55
|
+
}
|
|
56
|
+
getLibraryVersion(): string {
|
|
57
|
+
return version
|
|
58
|
+
}
|
|
59
|
+
getCustomUserAgent(): string {
|
|
60
|
+
return 'posthog-core-tests'
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const createTestClient = (
|
|
65
|
+
apiKey: string,
|
|
66
|
+
options?: PostHogCoreOptions,
|
|
67
|
+
setupMocks?: (mocks: PostHogCoreTestClientMocks) => void,
|
|
68
|
+
storageCache: { [key: string]: string | JsonType } = {}
|
|
69
|
+
): [PostHogCoreTestClient, PostHogCoreTestClientMocks] => {
|
|
70
|
+
const mocks = {
|
|
71
|
+
fetch: jest.fn(),
|
|
72
|
+
storage: {
|
|
73
|
+
getItem: jest.fn((key) => storageCache[key]),
|
|
74
|
+
setItem: jest.fn((key, val) => {
|
|
75
|
+
storageCache[key] = val == null ? undefined : val
|
|
76
|
+
}),
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
mocks.fetch.mockImplementation(() =>
|
|
81
|
+
Promise.resolve({
|
|
82
|
+
status: 200,
|
|
83
|
+
text: () => Promise.resolve('ok'),
|
|
84
|
+
json: () => Promise.resolve({ status: 'ok' }),
|
|
85
|
+
})
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
setupMocks?.(mocks)
|
|
89
|
+
|
|
90
|
+
return [new PostHogCoreTestClient(mocks, apiKey, { disableCompression: true, ...options }), mocks]
|
|
91
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Logger } from '@/types'
|
|
2
|
+
|
|
3
|
+
export const wait = async (t: number): Promise<void> => {
|
|
4
|
+
await new Promise((r) => setTimeout(r, t))
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const waitForPromises = async (): Promise<void> => {
|
|
8
|
+
await new Promise((resolve) => {
|
|
9
|
+
// IMPORTANT: Only enable real timers for this promise - allows us to pass a short amount of ticks
|
|
10
|
+
// whilst keeping any timers made during other promises as fake timers
|
|
11
|
+
jest.useRealTimers()
|
|
12
|
+
setTimeout(resolve, 10)
|
|
13
|
+
jest.useFakeTimers()
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const parseBody = (mockCall: any): any => {
|
|
18
|
+
const options = mockCall[1]
|
|
19
|
+
expect(options.method).toBe('POST')
|
|
20
|
+
return JSON.parse(options.body || '')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const createImperativePromise = <T>(): [Promise<T>, (value: T) => void] => {
|
|
24
|
+
let resolve: (value: T) => void
|
|
25
|
+
const promise = new Promise<T>((r) => {
|
|
26
|
+
resolve = r
|
|
27
|
+
})
|
|
28
|
+
return [promise, (val) => resolve?.(val)]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const delay = (ms: number): Promise<void> => {
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
setTimeout(resolve, ms)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const createMockLogger = (): Logger => {
|
|
38
|
+
return {
|
|
39
|
+
_log: jest.fn(),
|
|
40
|
+
info: jest.fn(),
|
|
41
|
+
warn: jest.fn(),
|
|
42
|
+
error: jest.fn(),
|
|
43
|
+
critical: jest.fn(),
|
|
44
|
+
uninitializedWarning: jest.fn(),
|
|
45
|
+
createLogger: createMockLogger,
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
export type PostHogCoreOptions = {
|
|
2
|
+
/** PostHog API host, usually 'https://us.i.posthog.com' or 'https://eu.i.posthog.com' */
|
|
3
|
+
host?: string
|
|
4
|
+
/** The number of events to queue before sending to PostHog (flushing) */
|
|
5
|
+
flushAt?: number
|
|
6
|
+
/** The interval in milliseconds between periodic flushes */
|
|
7
|
+
flushInterval?: number
|
|
8
|
+
/** The maximum number of queued messages to be flushed as part of a single batch (must be higher than `flushAt`) */
|
|
9
|
+
maxBatchSize?: number
|
|
10
|
+
/** The maximum number of cached messages either in memory or on the local storage.
|
|
11
|
+
* Defaults to 1000, (must be higher than `flushAt`)
|
|
12
|
+
*/
|
|
13
|
+
maxQueueSize?: number
|
|
14
|
+
/** If set to true the SDK is essentially disabled (useful for local environments where you don't want to track anything) */
|
|
15
|
+
disabled?: boolean
|
|
16
|
+
/** If set to false the SDK will not track until the `optIn` function is called. */
|
|
17
|
+
defaultOptIn?: boolean
|
|
18
|
+
/** Whether to track that `getFeatureFlag` was called (used by Experiments) */
|
|
19
|
+
sendFeatureFlagEvent?: boolean
|
|
20
|
+
/** Whether to load feature flags when initialized or not */
|
|
21
|
+
preloadFeatureFlags?: boolean
|
|
22
|
+
/**
|
|
23
|
+
* Whether to load remote config when initialized or not
|
|
24
|
+
* Experimental support
|
|
25
|
+
* Default: false - Remote config is loaded by default
|
|
26
|
+
*/
|
|
27
|
+
disableRemoteConfig?: boolean
|
|
28
|
+
/**
|
|
29
|
+
* Whether to load surveys when initialized or not
|
|
30
|
+
* Experimental support
|
|
31
|
+
* Default: false - Surveys are loaded by default, but requires the `PostHogSurveyProvider` to be used
|
|
32
|
+
*/
|
|
33
|
+
disableSurveys?: boolean
|
|
34
|
+
/** Option to bootstrap the library with given distinctId and feature flags */
|
|
35
|
+
bootstrap?: {
|
|
36
|
+
distinctId?: string
|
|
37
|
+
isIdentifiedId?: boolean
|
|
38
|
+
featureFlags?: Record<string, FeatureFlagValue>
|
|
39
|
+
featureFlagPayloads?: Record<string, JsonType>
|
|
40
|
+
}
|
|
41
|
+
/** How many times we will retry HTTP requests. Defaults to 3. */
|
|
42
|
+
fetchRetryCount?: number
|
|
43
|
+
/** The delay between HTTP request retries, Defaults to 3 seconds. */
|
|
44
|
+
fetchRetryDelay?: number
|
|
45
|
+
/** Timeout in milliseconds for any calls. Defaults to 10 seconds. */
|
|
46
|
+
requestTimeout?: number
|
|
47
|
+
/** Timeout in milliseconds for feature flag calls. Defaults to 10 seconds for stateful clients, and 3 seconds for stateless. */
|
|
48
|
+
featureFlagsRequestTimeoutMs?: number
|
|
49
|
+
/** Timeout in milliseconds for remote config calls. Defaults to 3 seconds. */
|
|
50
|
+
remoteConfigRequestTimeoutMs?: number
|
|
51
|
+
/** For Session Analysis how long before we expire a session (defaults to 30 mins) */
|
|
52
|
+
sessionExpirationTimeSeconds?: number
|
|
53
|
+
/** Whether to disable GZIP compression */
|
|
54
|
+
disableCompression?: boolean
|
|
55
|
+
disableGeoip?: boolean
|
|
56
|
+
/** Special flag to indicate ingested data is for a historical migration. */
|
|
57
|
+
historicalMigration?: boolean
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export enum PostHogPersistedProperty {
|
|
61
|
+
AnonymousId = 'anonymous_id',
|
|
62
|
+
DistinctId = 'distinct_id',
|
|
63
|
+
Props = 'props',
|
|
64
|
+
FeatureFlagDetails = 'feature_flag_details',
|
|
65
|
+
FeatureFlags = 'feature_flags',
|
|
66
|
+
FeatureFlagPayloads = 'feature_flag_payloads',
|
|
67
|
+
BootstrapFeatureFlagDetails = 'bootstrap_feature_flag_details',
|
|
68
|
+
BootstrapFeatureFlags = 'bootstrap_feature_flags',
|
|
69
|
+
BootstrapFeatureFlagPayloads = 'bootstrap_feature_flag_payloads',
|
|
70
|
+
OverrideFeatureFlags = 'override_feature_flags',
|
|
71
|
+
Queue = 'queue',
|
|
72
|
+
OptedOut = 'opted_out',
|
|
73
|
+
SessionId = 'session_id',
|
|
74
|
+
SessionStartTimestamp = 'session_start_timestamp',
|
|
75
|
+
SessionLastTimestamp = 'session_timestamp',
|
|
76
|
+
PersonProperties = 'person_properties',
|
|
77
|
+
GroupProperties = 'group_properties',
|
|
78
|
+
InstalledAppBuild = 'installed_app_build', // only used by posthog-react-native
|
|
79
|
+
InstalledAppVersion = 'installed_app_version', // only used by posthog-react-native
|
|
80
|
+
SessionReplay = 'session_replay', // only used by posthog-react-native
|
|
81
|
+
SurveyLastSeenDate = 'survey_last_seen_date', // only used by posthog-react-native
|
|
82
|
+
SurveysSeen = 'surveys_seen', // only used by posthog-react-native
|
|
83
|
+
Surveys = 'surveys', // only used by posthog-react-native
|
|
84
|
+
RemoteConfig = 'remote_config',
|
|
85
|
+
FlagsEndpointWasHit = 'flags_endpoint_was_hit', // only used by posthog-react-native
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type PostHogFetchOptions = {
|
|
89
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH'
|
|
90
|
+
mode?: 'no-cors'
|
|
91
|
+
credentials?: 'omit'
|
|
92
|
+
headers: { [key: string]: string }
|
|
93
|
+
body?: string | Blob
|
|
94
|
+
signal?: AbortSignal
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check out posthog-js for these additional options and try to keep them in sync
|
|
98
|
+
export type PostHogCaptureOptions = {
|
|
99
|
+
/** If provided overrides the auto-generated event ID */
|
|
100
|
+
uuid?: string
|
|
101
|
+
/** If provided overrides the auto-generated timestamp */
|
|
102
|
+
timestamp?: Date
|
|
103
|
+
disableGeoip?: boolean
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type PostHogFetchResponse = {
|
|
107
|
+
status: number
|
|
108
|
+
text: () => Promise<string>
|
|
109
|
+
json: () => Promise<any>
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type PostHogQueueItem = {
|
|
113
|
+
message: any
|
|
114
|
+
callback?: (err: any) => void
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type PostHogEventProperties = {
|
|
118
|
+
[key: string]: JsonType
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type PostHogGroupProperties = {
|
|
122
|
+
[type: string]: string | number
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type PostHogAutocaptureElement = {
|
|
126
|
+
$el_text?: string
|
|
127
|
+
tag_name: string
|
|
128
|
+
href?: string
|
|
129
|
+
nth_child?: number
|
|
130
|
+
nth_of_type?: number
|
|
131
|
+
order?: number
|
|
132
|
+
} & PostHogEventProperties
|
|
133
|
+
// Any key prefixed with `attr__` can be added
|
|
134
|
+
|
|
135
|
+
export enum Compression {
|
|
136
|
+
GZipJS = 'gzip-js',
|
|
137
|
+
Base64 = 'base64',
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export type PostHogRemoteConfig = {
|
|
141
|
+
sessionRecording?:
|
|
142
|
+
| boolean
|
|
143
|
+
| {
|
|
144
|
+
[key: string]: JsonType
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Supported compression algorithms
|
|
149
|
+
*/
|
|
150
|
+
supportedCompression?: Compression[]
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Whether surveys are enabled
|
|
154
|
+
*/
|
|
155
|
+
surveys?: boolean | Survey[]
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Indicates if the team has any flags enabled (if not we don't need to load them)
|
|
159
|
+
*/
|
|
160
|
+
hasFeatureFlags?: boolean
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export type FeatureFlagValue = string | boolean
|
|
164
|
+
|
|
165
|
+
export type PostHogFlagsResponse = Omit<PostHogRemoteConfig, 'surveys' | 'hasFeatureFlags'> & {
|
|
166
|
+
featureFlags: {
|
|
167
|
+
[key: string]: FeatureFlagValue
|
|
168
|
+
}
|
|
169
|
+
featureFlagPayloads: {
|
|
170
|
+
[key: string]: JsonType
|
|
171
|
+
}
|
|
172
|
+
flags: {
|
|
173
|
+
[key: string]: FeatureFlagDetail
|
|
174
|
+
}
|
|
175
|
+
errorsWhileComputingFlags: boolean
|
|
176
|
+
sessionRecording?:
|
|
177
|
+
| boolean
|
|
178
|
+
| {
|
|
179
|
+
[key: string]: JsonType
|
|
180
|
+
}
|
|
181
|
+
quotaLimited?: string[]
|
|
182
|
+
requestId?: string
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type PostHogFeatureFlagsResponse = PartialWithRequired<
|
|
186
|
+
PostHogFlagsResponse,
|
|
187
|
+
'flags' | 'featureFlags' | 'featureFlagPayloads' | 'requestId'
|
|
188
|
+
>
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Creates a type with all properties of T, but makes only K properties required while the rest remain optional.
|
|
192
|
+
*
|
|
193
|
+
* @template T - The base type containing all properties
|
|
194
|
+
* @template K - Union type of keys from T that should be required
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* interface User {
|
|
198
|
+
* id: number;
|
|
199
|
+
* name: string;
|
|
200
|
+
* email?: string;
|
|
201
|
+
* age?: number;
|
|
202
|
+
* }
|
|
203
|
+
*
|
|
204
|
+
* // Makes 'id' and 'name' required, but 'email' and 'age' optional
|
|
205
|
+
* type RequiredUser = PartialWithRequired<User, 'id' | 'name'>;
|
|
206
|
+
*
|
|
207
|
+
* const user: RequiredUser = {
|
|
208
|
+
* id: 1, // Must be provided
|
|
209
|
+
* name: "John" // Must be provided
|
|
210
|
+
* // email and age are optional
|
|
211
|
+
* };
|
|
212
|
+
*/
|
|
213
|
+
export type PartialWithRequired<T, K extends keyof T> = {
|
|
214
|
+
[P in K]: T[P] // Required fields
|
|
215
|
+
} & {
|
|
216
|
+
[P in Exclude<keyof T, K>]?: T[P] // Optional fields
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* These are the fields we care about from PostHogFlagsResponse for feature flags.
|
|
221
|
+
*/
|
|
222
|
+
export type PostHogFeatureFlagDetails = PartialWithRequired<
|
|
223
|
+
PostHogFlagsResponse,
|
|
224
|
+
'flags' | 'featureFlags' | 'featureFlagPayloads' | 'requestId'
|
|
225
|
+
>
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Models the response from the v1 `/flags` endpoint.
|
|
229
|
+
*/
|
|
230
|
+
export type PostHogV1FlagsResponse = Omit<PostHogFlagsResponse, 'flags'>
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Models the response from the v2 `/flags` endpoint.
|
|
234
|
+
*/
|
|
235
|
+
export type PostHogV2FlagsResponse = Omit<PostHogFlagsResponse, 'featureFlags' | 'featureFlagPayloads'>
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* The format of the flags object in persisted storage
|
|
239
|
+
*
|
|
240
|
+
* When we pull flags from persistence, we can normalize them to PostHogFeatureFlagDetails
|
|
241
|
+
* so that we can support v1 and v2 of the API.
|
|
242
|
+
*/
|
|
243
|
+
export type PostHogFlagsStorageFormat = Pick<PostHogFeatureFlagDetails, 'flags'>
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Models legacy flags and payloads return type for many public methods.
|
|
247
|
+
*/
|
|
248
|
+
export type PostHogFlagsAndPayloadsResponse = Partial<
|
|
249
|
+
Pick<PostHogFlagsResponse, 'featureFlags' | 'featureFlagPayloads'>
|
|
250
|
+
>
|
|
251
|
+
|
|
252
|
+
export type JsonType = string | number | boolean | null | { [key: string]: JsonType } | Array<JsonType> | JsonType[]
|
|
253
|
+
|
|
254
|
+
export type FetchLike = (url: string, options: PostHogFetchOptions) => Promise<PostHogFetchResponse>
|
|
255
|
+
|
|
256
|
+
export type FeatureFlagDetail = {
|
|
257
|
+
key: string
|
|
258
|
+
enabled: boolean
|
|
259
|
+
variant: string | undefined
|
|
260
|
+
reason: EvaluationReason | undefined
|
|
261
|
+
metadata: FeatureFlagMetadata | undefined
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export type FeatureFlagMetadata = {
|
|
265
|
+
id: number | undefined
|
|
266
|
+
version: number | undefined
|
|
267
|
+
description: string | undefined
|
|
268
|
+
// Payloads in the response are always JSON encoded as a string
|
|
269
|
+
payload: string | undefined
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export type EvaluationReason = {
|
|
273
|
+
code: string | undefined
|
|
274
|
+
condition_index: number | undefined
|
|
275
|
+
description: string | undefined
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// survey types
|
|
279
|
+
export type SurveyAppearance = {
|
|
280
|
+
// keep in sync with frontend/src/types.ts -> SurveyAppearance
|
|
281
|
+
backgroundColor?: string
|
|
282
|
+
submitButtonColor?: string
|
|
283
|
+
// deprecate submit button text eventually
|
|
284
|
+
submitButtonText?: string
|
|
285
|
+
submitButtonTextColor?: string
|
|
286
|
+
ratingButtonColor?: string
|
|
287
|
+
ratingButtonActiveColor?: string
|
|
288
|
+
autoDisappear?: boolean
|
|
289
|
+
displayThankYouMessage?: boolean
|
|
290
|
+
thankYouMessageHeader?: string
|
|
291
|
+
thankYouMessageDescription?: string
|
|
292
|
+
thankYouMessageDescriptionContentType?: SurveyQuestionDescriptionContentType
|
|
293
|
+
thankYouMessageCloseButtonText?: string
|
|
294
|
+
borderColor?: string
|
|
295
|
+
position?: SurveyPosition
|
|
296
|
+
placeholder?: string
|
|
297
|
+
shuffleQuestions?: boolean
|
|
298
|
+
surveyPopupDelaySeconds?: number
|
|
299
|
+
// widget options
|
|
300
|
+
widgetType?: SurveyWidgetType
|
|
301
|
+
widgetSelector?: string
|
|
302
|
+
widgetLabel?: string
|
|
303
|
+
widgetColor?: string
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export enum SurveyPosition {
|
|
307
|
+
TopLeft = 'top_left',
|
|
308
|
+
TopCenter = 'top_center',
|
|
309
|
+
TopRight = 'top_right',
|
|
310
|
+
MiddleLeft = 'middle_left',
|
|
311
|
+
MiddleCenter = 'middle_center',
|
|
312
|
+
MiddleRight = 'middle_right',
|
|
313
|
+
Left = 'left',
|
|
314
|
+
Right = 'right',
|
|
315
|
+
Center = 'center',
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export enum SurveyWidgetType {
|
|
319
|
+
Button = 'button',
|
|
320
|
+
Tab = 'tab',
|
|
321
|
+
Selector = 'selector',
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export enum SurveyType {
|
|
325
|
+
Popover = 'popover',
|
|
326
|
+
API = 'api',
|
|
327
|
+
Widget = 'widget',
|
|
328
|
+
ExternalSurvey = 'external_survey',
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export type SurveyQuestion = BasicSurveyQuestion | LinkSurveyQuestion | RatingSurveyQuestion | MultipleSurveyQuestion
|
|
332
|
+
|
|
333
|
+
export enum SurveyQuestionDescriptionContentType {
|
|
334
|
+
Html = 'html',
|
|
335
|
+
Text = 'text',
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
type SurveyQuestionBase = {
|
|
339
|
+
question: string
|
|
340
|
+
id?: string // TODO: use this for the question id
|
|
341
|
+
description?: string
|
|
342
|
+
descriptionContentType?: SurveyQuestionDescriptionContentType
|
|
343
|
+
optional?: boolean
|
|
344
|
+
buttonText?: string
|
|
345
|
+
originalQuestionIndex: number
|
|
346
|
+
branching?: NextQuestionBranching | EndBranching | ResponseBasedBranching | SpecificQuestionBranching
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export type BasicSurveyQuestion = SurveyQuestionBase & {
|
|
350
|
+
type: SurveyQuestionType.Open
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export type LinkSurveyQuestion = SurveyQuestionBase & {
|
|
354
|
+
type: SurveyQuestionType.Link
|
|
355
|
+
link?: string
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export type RatingSurveyQuestion = SurveyQuestionBase & {
|
|
359
|
+
type: SurveyQuestionType.Rating
|
|
360
|
+
display: SurveyRatingDisplay
|
|
361
|
+
scale: 3 | 5 | 7 | 10
|
|
362
|
+
lowerBoundLabel: string
|
|
363
|
+
upperBoundLabel: string
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export enum SurveyRatingDisplay {
|
|
367
|
+
Number = 'number',
|
|
368
|
+
Emoji = 'emoji',
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export type MultipleSurveyQuestion = SurveyQuestionBase & {
|
|
372
|
+
type: SurveyQuestionType.SingleChoice | SurveyQuestionType.MultipleChoice
|
|
373
|
+
choices: string[]
|
|
374
|
+
hasOpenChoice?: boolean
|
|
375
|
+
shuffleOptions?: boolean
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
export enum SurveyQuestionType {
|
|
379
|
+
Open = 'open',
|
|
380
|
+
MultipleChoice = 'multiple_choice',
|
|
381
|
+
SingleChoice = 'single_choice',
|
|
382
|
+
Rating = 'rating',
|
|
383
|
+
Link = 'link',
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export enum SurveyQuestionBranchingType {
|
|
387
|
+
NextQuestion = 'next_question',
|
|
388
|
+
End = 'end',
|
|
389
|
+
ResponseBased = 'response_based',
|
|
390
|
+
SpecificQuestion = 'specific_question',
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export type NextQuestionBranching = {
|
|
394
|
+
type: SurveyQuestionBranchingType.NextQuestion
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export type EndBranching = {
|
|
398
|
+
type: SurveyQuestionBranchingType.End
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export type ResponseBasedBranching = {
|
|
402
|
+
type: SurveyQuestionBranchingType.ResponseBased
|
|
403
|
+
responseValues: Record<string, any>
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export type SpecificQuestionBranching = {
|
|
407
|
+
type: SurveyQuestionBranchingType.SpecificQuestion
|
|
408
|
+
index: number
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export type SurveyResponse = {
|
|
412
|
+
surveys: Survey[]
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export type SurveyCallback = (surveys: Survey[]) => void
|
|
416
|
+
|
|
417
|
+
export enum SurveyMatchType {
|
|
418
|
+
Regex = 'regex',
|
|
419
|
+
NotRegex = 'not_regex',
|
|
420
|
+
Exact = 'exact',
|
|
421
|
+
IsNot = 'is_not',
|
|
422
|
+
Icontains = 'icontains',
|
|
423
|
+
NotIcontains = 'not_icontains',
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export type SurveyElement = {
|
|
427
|
+
text?: string
|
|
428
|
+
$el_text?: string
|
|
429
|
+
tag_name?: string
|
|
430
|
+
href?: string
|
|
431
|
+
attr_id?: string
|
|
432
|
+
attr_class?: string[]
|
|
433
|
+
nth_child?: number
|
|
434
|
+
nth_of_type?: number
|
|
435
|
+
attributes?: Record<string, any>
|
|
436
|
+
event_id?: number
|
|
437
|
+
order?: number
|
|
438
|
+
group_id?: number
|
|
439
|
+
}
|
|
440
|
+
export type SurveyRenderReason = {
|
|
441
|
+
visible: boolean
|
|
442
|
+
disabledReason?: string
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export type Survey = {
|
|
446
|
+
// Sync this with the backend's SurveyAPISerializer!
|
|
447
|
+
id: string
|
|
448
|
+
name: string
|
|
449
|
+
description?: string
|
|
450
|
+
type: SurveyType
|
|
451
|
+
feature_flag_keys?: {
|
|
452
|
+
key: string
|
|
453
|
+
value?: string
|
|
454
|
+
}[]
|
|
455
|
+
linked_flag_key?: string
|
|
456
|
+
targeting_flag_key?: string
|
|
457
|
+
internal_targeting_flag_key?: string
|
|
458
|
+
questions: SurveyQuestion[]
|
|
459
|
+
appearance?: SurveyAppearance
|
|
460
|
+
conditions?: {
|
|
461
|
+
url?: string
|
|
462
|
+
selector?: string
|
|
463
|
+
seenSurveyWaitPeriodInDays?: number
|
|
464
|
+
urlMatchType?: SurveyMatchType
|
|
465
|
+
events?: {
|
|
466
|
+
repeatedActivation?: boolean
|
|
467
|
+
values?: {
|
|
468
|
+
name: string
|
|
469
|
+
}[]
|
|
470
|
+
}
|
|
471
|
+
actions?: {
|
|
472
|
+
values: SurveyActionType[]
|
|
473
|
+
}
|
|
474
|
+
deviceTypes?: string[]
|
|
475
|
+
deviceTypesMatchType?: SurveyMatchType
|
|
476
|
+
linkedFlagVariant?: string
|
|
477
|
+
}
|
|
478
|
+
start_date?: string
|
|
479
|
+
end_date?: string
|
|
480
|
+
current_iteration?: number
|
|
481
|
+
current_iteration_start_date?: string
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export type SurveyActionType = {
|
|
485
|
+
id: number
|
|
486
|
+
name?: string
|
|
487
|
+
steps?: ActionStepType[]
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** Sync with plugin-server/src/types.ts */
|
|
491
|
+
export enum ActionStepStringMatching {
|
|
492
|
+
Contains = 'contains',
|
|
493
|
+
Exact = 'exact',
|
|
494
|
+
Regex = 'regex',
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export type ActionStepType = {
|
|
498
|
+
event?: string
|
|
499
|
+
selector?: string
|
|
500
|
+
text?: string
|
|
501
|
+
/** @default StringMatching.Exact */
|
|
502
|
+
text_matching?: ActionStepStringMatching
|
|
503
|
+
href?: string
|
|
504
|
+
/** @default ActionStepStringMatching.Exact */
|
|
505
|
+
href_matching?: ActionStepStringMatching
|
|
506
|
+
url?: string
|
|
507
|
+
/** @default StringMatching.Contains */
|
|
508
|
+
url_matching?: ActionStepStringMatching
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export type Logger = {
|
|
512
|
+
_log: (level: 'log' | 'warn' | 'error', ...args: any[]) => void
|
|
513
|
+
info: (...args: any[]) => void
|
|
514
|
+
warn: (...args: any[]) => void
|
|
515
|
+
error: (...args: any[]) => void
|
|
516
|
+
critical: (...args: any[]) => void
|
|
517
|
+
uninitializedWarning: (methodName: string) => void
|
|
518
|
+
createLogger: (prefix: string) => Logger
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
export const knownUnsafeEditableEvent = [
|
|
522
|
+
'$snapshot',
|
|
523
|
+
'$pageview',
|
|
524
|
+
'$pageleave',
|
|
525
|
+
'$set',
|
|
526
|
+
'survey dismissed',
|
|
527
|
+
'survey sent',
|
|
528
|
+
'survey shown',
|
|
529
|
+
'$identify',
|
|
530
|
+
'$groupidentify',
|
|
531
|
+
'$create_alias',
|
|
532
|
+
'$$client_ingestion_warning',
|
|
533
|
+
'$web_experiment_applied',
|
|
534
|
+
'$feature_enrollment_update',
|
|
535
|
+
'$feature_flag_called',
|
|
536
|
+
] as const
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* These events can be processed by the `beforeCapture` function
|
|
540
|
+
* but can cause unexpected confusion in data.
|
|
541
|
+
*
|
|
542
|
+
* Some features of PostHog rely on receiving 100% of these events
|
|
543
|
+
*/
|
|
544
|
+
export type KnownUnsafeEditableEvent = (typeof knownUnsafeEditableEvent)[number]
|