@posthog/core 1.11.0 → 1.12.0
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/posthog-core-stateless.d.ts +11 -3
- package/dist/posthog-core-stateless.d.ts.map +1 -1
- package/dist/posthog-core-stateless.js +39 -5
- package/dist/posthog-core-stateless.mjs +39 -5
- package/dist/posthog-core.d.ts +23 -4
- package/dist/posthog-core.d.ts.map +1 -1
- package/dist/posthog-core.js +95 -16
- package/dist/posthog-core.mjs +96 -17
- package/dist/testing/PostHogCoreTestClient.d.ts +2 -2
- package/dist/testing/PostHogCoreTestClient.d.ts.map +1 -1
- package/dist/types.d.ts +76 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -0
- package/dist/types.mjs +10 -1
- package/package.json +1 -1
- package/src/posthog-core-stateless.ts +57 -11
- package/src/posthog-core.ts +168 -32
- package/src/testing/PostHogCoreTestClient.ts +2 -8
- package/src/types.ts +82 -1
package/src/posthog-core.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
PostHogAutocaptureElement,
|
|
3
3
|
PostHogFlagsResponse,
|
|
4
|
+
PostHogFeatureFlagsResponse,
|
|
4
5
|
PostHogCoreOptions,
|
|
5
6
|
PostHogEventProperties,
|
|
6
7
|
PostHogCaptureOptions,
|
|
@@ -15,6 +16,8 @@ import type {
|
|
|
15
16
|
Survey,
|
|
16
17
|
SurveyResponse,
|
|
17
18
|
PostHogGroupProperties,
|
|
19
|
+
BeforeSendFn,
|
|
20
|
+
CaptureEvent,
|
|
18
21
|
} from './types'
|
|
19
22
|
import {
|
|
20
23
|
createFlagsResponseFromFlagsAndPayloads,
|
|
@@ -24,7 +27,7 @@ import {
|
|
|
24
27
|
normalizeFlagsResponse,
|
|
25
28
|
updateFlagValue,
|
|
26
29
|
} from './featureFlagUtils'
|
|
27
|
-
import { Compression, PostHogPersistedProperty } from './types'
|
|
30
|
+
import { Compression, FeatureFlagError, PostHogPersistedProperty } from './types'
|
|
28
31
|
import { maybeAdd, PostHogCoreStateless, QuotaLimitedFeature } from './posthog-core-stateless'
|
|
29
32
|
import { uuidv7 } from './vendor/uuidv7'
|
|
30
33
|
import { isPlainError } from './utils'
|
|
@@ -33,9 +36,10 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
33
36
|
// options
|
|
34
37
|
private sendFeatureFlagEvent: boolean
|
|
35
38
|
private flagCallReported: { [key: string]: boolean } = {}
|
|
39
|
+
private _beforeSend?: BeforeSendFn | BeforeSendFn[]
|
|
36
40
|
|
|
37
41
|
// internal
|
|
38
|
-
protected _flagsResponsePromise?: Promise<
|
|
42
|
+
protected _flagsResponsePromise?: Promise<PostHogFeatureFlagsResponse | undefined>
|
|
39
43
|
protected _sessionExpirationTimeSeconds: number
|
|
40
44
|
private _sessionMaxLengthSeconds: number = 24 * 60 * 60 // 24 hours
|
|
41
45
|
protected sessionProps: PostHogEventProperties = {}
|
|
@@ -51,6 +55,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
51
55
|
|
|
52
56
|
this.sendFeatureFlagEvent = options?.sendFeatureFlagEvent ?? true
|
|
53
57
|
this._sessionExpirationTimeSeconds = options?.sessionExpirationTimeSeconds ?? 1800 // 30 minutes
|
|
58
|
+
this._beforeSend = options?.before_send
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
protected setupBootstrap(options?: Partial<PostHogCoreOptions>): void {
|
|
@@ -453,7 +458,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
453
458
|
protected async flagsAsync(
|
|
454
459
|
sendAnonDistinctId: boolean = true,
|
|
455
460
|
fetchConfig: boolean = true
|
|
456
|
-
): Promise<
|
|
461
|
+
): Promise<PostHogFeatureFlagsResponse | undefined> {
|
|
457
462
|
await this._initPromise
|
|
458
463
|
if (this._flagsResponsePromise) {
|
|
459
464
|
return this._flagsResponsePromise
|
|
@@ -551,7 +556,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
551
556
|
private async _flagsAsync(
|
|
552
557
|
sendAnonDistinctId: boolean = true,
|
|
553
558
|
fetchConfig: boolean = true
|
|
554
|
-
): Promise<
|
|
559
|
+
): Promise<PostHogFeatureFlagsResponse | undefined> {
|
|
555
560
|
this._flagsResponsePromise = this._initPromise
|
|
556
561
|
.then(async () => {
|
|
557
562
|
const distinctId = this.getDistinctId()
|
|
@@ -566,7 +571,7 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
566
571
|
$anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
|
|
567
572
|
}
|
|
568
573
|
|
|
569
|
-
const
|
|
574
|
+
const result = await super.getFlags(
|
|
570
575
|
distinctId,
|
|
571
576
|
groups as PostHogGroupProperties,
|
|
572
577
|
personProperties,
|
|
@@ -574,12 +579,24 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
574
579
|
extraProperties,
|
|
575
580
|
fetchConfig
|
|
576
581
|
)
|
|
577
|
-
|
|
582
|
+
|
|
583
|
+
if (!result.success) {
|
|
584
|
+
this.setKnownFeatureFlagDetails({
|
|
585
|
+
flags: this.getKnownFeatureFlagDetails()?.flags ?? {},
|
|
586
|
+
requestError: result.error,
|
|
587
|
+
})
|
|
588
|
+
return undefined
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const res = result.response
|
|
592
|
+
|
|
578
593
|
if (res?.quotaLimited?.includes(QuotaLimitedFeature.FeatureFlags)) {
|
|
579
|
-
|
|
580
|
-
|
|
594
|
+
this.setKnownFeatureFlagDetails({
|
|
595
|
+
flags: this.getKnownFeatureFlagDetails()?.flags ?? {},
|
|
596
|
+
quotaLimited: res.quotaLimited,
|
|
597
|
+
})
|
|
581
598
|
console.warn(
|
|
582
|
-
'[FEATURE FLAGS] Feature flags quota limit exceeded
|
|
599
|
+
'[FEATURE FLAGS] Feature flags quota limit exceeded. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts'
|
|
583
600
|
)
|
|
584
601
|
return res
|
|
585
602
|
}
|
|
@@ -600,7 +617,13 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
600
617
|
flags: { ...currentFlagDetails?.flags, ...res.flags },
|
|
601
618
|
}
|
|
602
619
|
}
|
|
603
|
-
this.setKnownFeatureFlagDetails(
|
|
620
|
+
this.setKnownFeatureFlagDetails({
|
|
621
|
+
flags: newFeatureFlagDetails.flags,
|
|
622
|
+
requestId: res.requestId,
|
|
623
|
+
evaluatedAt: res.evaluatedAt,
|
|
624
|
+
errorsWhileComputingFlags: res.errorsWhileComputingFlags,
|
|
625
|
+
quotaLimited: res.quotaLimited,
|
|
626
|
+
})
|
|
604
627
|
// Mark that we hit the /flags endpoint so we can capture this in the $feature_flag_called event
|
|
605
628
|
this.setPersistedProperty(PostHogPersistedProperty.FlagsEndpointWasHit, true)
|
|
606
629
|
this.cacheSessionReplay('flags', res)
|
|
@@ -613,7 +636,6 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
613
636
|
return this._flagsResponsePromise
|
|
614
637
|
}
|
|
615
638
|
|
|
616
|
-
// We only store the flags and request id in the feature flag details storage key
|
|
617
639
|
private setKnownFeatureFlagDetails(flagsResponse: PostHogFlagsStorageFormat | null): void {
|
|
618
640
|
this.wrap(() => {
|
|
619
641
|
this.setPersistedProperty<PostHogFlagsStorageFormat>(PostHogPersistedProperty.FeatureFlagDetails, flagsResponse)
|
|
@@ -647,20 +669,16 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
647
669
|
) as PostHogFeatureFlagDetails
|
|
648
670
|
}
|
|
649
671
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
if (!featureFlagDetails) {
|
|
653
|
-
return undefined
|
|
654
|
-
}
|
|
655
|
-
return getFlagValuesFromFlags(featureFlagDetails.flags)
|
|
672
|
+
private getStoredFlagDetails(): PostHogFlagsStorageFormat | undefined {
|
|
673
|
+
return this.getPersistedProperty<PostHogFlagsStorageFormat>(PostHogPersistedProperty.FeatureFlagDetails)
|
|
656
674
|
}
|
|
657
675
|
|
|
658
|
-
|
|
676
|
+
protected getKnownFeatureFlags(): PostHogFlagsResponse['featureFlags'] | undefined {
|
|
659
677
|
const featureFlagDetails = this.getKnownFeatureFlagDetails()
|
|
660
678
|
if (!featureFlagDetails) {
|
|
661
679
|
return undefined
|
|
662
680
|
}
|
|
663
|
-
return
|
|
681
|
+
return getFlagValuesFromFlags(featureFlagDetails.flags)
|
|
664
682
|
}
|
|
665
683
|
|
|
666
684
|
private getBootstrappedFeatureFlagDetails(): PostHogFeatureFlagDetails | undefined {
|
|
@@ -694,28 +712,58 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
694
712
|
}
|
|
695
713
|
|
|
696
714
|
getFeatureFlag(key: string): FeatureFlagValue | undefined {
|
|
715
|
+
const storedDetails = this.getStoredFlagDetails()
|
|
697
716
|
const details = this.getFeatureFlagDetails()
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
717
|
+
const errors: string[] = []
|
|
718
|
+
const isQuotaLimited = storedDetails?.quotaLimited?.includes(QuotaLimitedFeature.FeatureFlags)
|
|
719
|
+
|
|
720
|
+
if (storedDetails?.requestError) {
|
|
721
|
+
const { type, statusCode } = storedDetails.requestError
|
|
722
|
+
if (type === 'timeout') {
|
|
723
|
+
errors.push(FeatureFlagError.TIMEOUT)
|
|
724
|
+
} else if (type === 'api_error' && statusCode !== undefined) {
|
|
725
|
+
errors.push(FeatureFlagError.apiError(statusCode))
|
|
726
|
+
} else if (type === 'connection_error') {
|
|
727
|
+
errors.push(FeatureFlagError.CONNECTION_ERROR)
|
|
728
|
+
} else {
|
|
729
|
+
errors.push(FeatureFlagError.UNKNOWN_ERROR)
|
|
730
|
+
}
|
|
731
|
+
} else if (storedDetails) {
|
|
732
|
+
if (storedDetails.errorsWhileComputingFlags) {
|
|
733
|
+
errors.push(FeatureFlagError.ERRORS_WHILE_COMPUTING)
|
|
734
|
+
}
|
|
735
|
+
if (isQuotaLimited) {
|
|
736
|
+
errors.push(FeatureFlagError.QUOTA_LIMITED)
|
|
737
|
+
}
|
|
702
738
|
}
|
|
703
739
|
|
|
704
|
-
const featureFlag = details
|
|
740
|
+
const featureFlag = details?.flags[key]
|
|
705
741
|
|
|
706
|
-
let response = getFeatureFlagValue(featureFlag)
|
|
742
|
+
let response: FeatureFlagValue | undefined = getFeatureFlagValue(featureFlag)
|
|
707
743
|
|
|
708
744
|
if (response === undefined) {
|
|
709
|
-
//
|
|
710
|
-
|
|
745
|
+
// Return false for missing flags when we have successfully loaded flags.
|
|
746
|
+
const hasCachedFlags = details && Object.keys(details.flags).length > 0
|
|
747
|
+
if (hasCachedFlags) {
|
|
748
|
+
response = false
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Track missing flags only when we had a successful, non-limited request.
|
|
752
|
+
// When quota limited or request failed, we cannot determine if the flag is truly missing.
|
|
753
|
+
if (details && !featureFlag && !storedDetails?.requestError && !isQuotaLimited) {
|
|
754
|
+
errors.push(FeatureFlagError.FLAG_MISSING)
|
|
755
|
+
}
|
|
711
756
|
}
|
|
712
757
|
|
|
713
758
|
if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
|
|
714
759
|
const bootstrappedResponse = this.getBootstrappedFeatureFlags()?.[key]
|
|
715
760
|
const bootstrappedPayload = this.getBootstrappedFeatureFlagPayloads()?.[key]
|
|
716
761
|
|
|
762
|
+
const featureFlagError = errors.length > 0 ? errors.join(',') : undefined
|
|
763
|
+
|
|
717
764
|
this.flagCallReported[key] = true
|
|
718
|
-
|
|
765
|
+
|
|
766
|
+
const properties: Record<string, any> = {
|
|
719
767
|
$feature_flag: key,
|
|
720
768
|
$feature_flag_response: response,
|
|
721
769
|
...maybeAdd('$feature_flag_id', featureFlag?.metadata?.id),
|
|
@@ -725,12 +773,14 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
725
773
|
...maybeAdd('$feature_flag_bootstrapped_payload', bootstrappedPayload),
|
|
726
774
|
// If we haven't yet received a response from the /flags endpoint, we must have used the bootstrapped value
|
|
727
775
|
$used_bootstrap_value: !this.getPersistedProperty(PostHogPersistedProperty.FlagsEndpointWasHit),
|
|
728
|
-
...maybeAdd('$feature_flag_request_id', details
|
|
729
|
-
...maybeAdd('$feature_flag_evaluated_at', details
|
|
730
|
-
|
|
776
|
+
...maybeAdd('$feature_flag_request_id', details?.requestId),
|
|
777
|
+
...maybeAdd('$feature_flag_evaluated_at', details?.evaluatedAt),
|
|
778
|
+
...maybeAdd('$feature_flag_error', featureFlagError),
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
this.capture('$feature_flag_called', properties)
|
|
731
782
|
}
|
|
732
783
|
|
|
733
|
-
// If we have flags we either return the value (true or string) or false
|
|
734
784
|
return response
|
|
735
785
|
}
|
|
736
786
|
|
|
@@ -950,4 +1000,90 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
950
1000
|
$ai_trace_id: String(traceId),
|
|
951
1001
|
})
|
|
952
1002
|
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Override processBeforeEnqueue to run before_send hooks.
|
|
1006
|
+
* This runs after prepareMessage, giving users full control over the final event.
|
|
1007
|
+
*
|
|
1008
|
+
* The internal message contains many fields (event, distinct_id, properties, type, library,
|
|
1009
|
+
* library_version, timestamp, uuid). CaptureEvent exposes a subset matching the web SDK's
|
|
1010
|
+
* CaptureResult: uuid, event, properties, $set, $set_once, timestamp.
|
|
1011
|
+
* Note: $set/$set_once are extracted from properties.$set and properties.$set_once.
|
|
1012
|
+
*/
|
|
1013
|
+
protected processBeforeEnqueue(message: PostHogEventProperties): PostHogEventProperties | null {
|
|
1014
|
+
if (!this._beforeSend) {
|
|
1015
|
+
return message
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Convert internal message format to CaptureEvent (user-facing interface matching web SDK's CaptureResult)
|
|
1019
|
+
const timestamp = message.timestamp
|
|
1020
|
+
const props = (message.properties || {}) as PostHogEventProperties
|
|
1021
|
+
const captureEvent: CaptureEvent = {
|
|
1022
|
+
uuid: message.uuid as string,
|
|
1023
|
+
event: message.event as string,
|
|
1024
|
+
properties: props,
|
|
1025
|
+
$set: props.$set as PostHogEventProperties | undefined,
|
|
1026
|
+
$set_once: props.$set_once as PostHogEventProperties | undefined,
|
|
1027
|
+
// Convert timestamp to Date if it's a string (from currentISOTime())
|
|
1028
|
+
timestamp: typeof timestamp === 'string' ? new Date(timestamp) : (timestamp as unknown as Date | undefined),
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
const result = this._runBeforeSend(captureEvent)
|
|
1032
|
+
|
|
1033
|
+
if (!result) {
|
|
1034
|
+
return null
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// Apply modifications from CaptureEvent back to internal message
|
|
1038
|
+
// Put $set/$set_once back into properties where they belong
|
|
1039
|
+
const resultProps = { ...(result.properties ?? props) } as PostHogEventProperties
|
|
1040
|
+
if (result.$set !== undefined) {
|
|
1041
|
+
resultProps.$set = result.$set as JsonType
|
|
1042
|
+
} else {
|
|
1043
|
+
delete resultProps.$set
|
|
1044
|
+
}
|
|
1045
|
+
if (result.$set_once !== undefined) {
|
|
1046
|
+
resultProps.$set_once = result.$set_once as JsonType
|
|
1047
|
+
} else {
|
|
1048
|
+
delete resultProps.$set_once
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
return {
|
|
1052
|
+
...message,
|
|
1053
|
+
uuid: result.uuid ?? message.uuid,
|
|
1054
|
+
event: result.event,
|
|
1055
|
+
properties: resultProps,
|
|
1056
|
+
timestamp: result.timestamp as unknown as JsonType,
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Runs the before_send hook(s) on the given capture event.
|
|
1062
|
+
* If any hook returns null, the event is dropped.
|
|
1063
|
+
*
|
|
1064
|
+
* @param captureEvent The event to process
|
|
1065
|
+
* @returns The processed event, or null if the event should be dropped
|
|
1066
|
+
*/
|
|
1067
|
+
private _runBeforeSend(captureEvent: CaptureEvent): CaptureEvent | null {
|
|
1068
|
+
const beforeSend = this._beforeSend
|
|
1069
|
+
if (!beforeSend) {
|
|
1070
|
+
return captureEvent
|
|
1071
|
+
}
|
|
1072
|
+
const fns = Array.isArray(beforeSend) ? beforeSend : [beforeSend]
|
|
1073
|
+
let result: CaptureEvent | null = captureEvent
|
|
1074
|
+
|
|
1075
|
+
for (const fn of fns) {
|
|
1076
|
+
try {
|
|
1077
|
+
result = fn(result)
|
|
1078
|
+
if (!result) {
|
|
1079
|
+
this._logger.info(`Event '${captureEvent.event}' was rejected in before_send function`)
|
|
1080
|
+
return null
|
|
1081
|
+
}
|
|
1082
|
+
} catch (e) {
|
|
1083
|
+
this._logger.error(`Error in before_send function for event '${captureEvent.event}':`, e)
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
return result
|
|
1088
|
+
}
|
|
953
1089
|
}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { PostHogCore } from '@/posthog-core'
|
|
2
|
-
import type {
|
|
3
|
-
JsonType,
|
|
4
|
-
PostHogCoreOptions,
|
|
5
|
-
PostHogFetchOptions,
|
|
6
|
-
PostHogFetchResponse,
|
|
7
|
-
PostHogFlagsResponse,
|
|
8
|
-
} from '@/types'
|
|
2
|
+
import type { GetFlagsResult, JsonType, PostHogCoreOptions, PostHogFetchOptions, PostHogFetchResponse } from '@/types'
|
|
9
3
|
|
|
10
4
|
const version = '2.0.0-alpha'
|
|
11
5
|
|
|
@@ -37,7 +31,7 @@ export class PostHogCoreTestClient extends PostHogCore {
|
|
|
37
31
|
personProperties: Record<string, string> = {},
|
|
38
32
|
groupProperties: Record<string, Record<string, string>> = {},
|
|
39
33
|
extraPayload: Record<string, any> = {}
|
|
40
|
-
): Promise<
|
|
34
|
+
): Promise<GetFlagsResult> {
|
|
41
35
|
return super.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload)
|
|
42
36
|
}
|
|
43
37
|
|
package/src/types.ts
CHANGED
|
@@ -71,6 +71,12 @@ export type PostHogCoreOptions = {
|
|
|
71
71
|
* @deprecated Use evaluationContexts instead. This property will be removed in a future version.
|
|
72
72
|
*/
|
|
73
73
|
evaluationEnvironments?: readonly string[]
|
|
74
|
+
/**
|
|
75
|
+
* Allows modification or dropping of events before they're sent to PostHog.
|
|
76
|
+
* If an array is provided, the functions are run in order.
|
|
77
|
+
* If a function returns null, the event will be dropped.
|
|
78
|
+
*/
|
|
79
|
+
before_send?: BeforeSendFn | BeforeSendFn[]
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
export enum PostHogPersistedProperty {
|
|
@@ -260,7 +266,12 @@ export type PostHogV2FlagsResponse = Omit<PostHogFlagsResponse, 'featureFlags' |
|
|
|
260
266
|
* When we pull flags from persistence, we can normalize them to PostHogFeatureFlagDetails
|
|
261
267
|
* so that we can support v1 and v2 of the API.
|
|
262
268
|
*/
|
|
263
|
-
export type PostHogFlagsStorageFormat = Pick<PostHogFeatureFlagDetails, 'flags'>
|
|
269
|
+
export type PostHogFlagsStorageFormat = Pick<PostHogFeatureFlagDetails, 'flags'> &
|
|
270
|
+
Partial<Pick<PostHogFlagsResponse, 'requestId' | 'evaluatedAt'>> & {
|
|
271
|
+
errorsWhileComputingFlags?: boolean
|
|
272
|
+
quotaLimited?: string[]
|
|
273
|
+
requestError?: FeatureFlagRequestError
|
|
274
|
+
}
|
|
264
275
|
|
|
265
276
|
/**
|
|
266
277
|
* Models legacy flags and payloads return type for many public methods.
|
|
@@ -273,6 +284,51 @@ export type JsonType = string | number | boolean | null | { [key: string]: JsonT
|
|
|
273
284
|
|
|
274
285
|
export type FetchLike = (url: string, options: PostHogFetchOptions) => Promise<PostHogFetchResponse>
|
|
275
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Error type constants for the $feature_flag_error property.
|
|
289
|
+
*
|
|
290
|
+
* These values are sent in analytics events to track flag evaluation failures.
|
|
291
|
+
* They should not be changed without considering impact on existing dashboards
|
|
292
|
+
* and queries that filter on these values.
|
|
293
|
+
*
|
|
294
|
+
* Error values:
|
|
295
|
+
* ERRORS_WHILE_COMPUTING: Server returned errorsWhileComputingFlags=true
|
|
296
|
+
* FLAG_MISSING: Requested flag not in API response
|
|
297
|
+
* QUOTA_LIMITED: Rate/quota limit exceeded
|
|
298
|
+
* TIMEOUT: Request timed out
|
|
299
|
+
* CONNECTION_ERROR: Network connection failed
|
|
300
|
+
* apiError: HTTP error with status code (e.g., api_error_500)
|
|
301
|
+
*/
|
|
302
|
+
export const FeatureFlagError = {
|
|
303
|
+
ERRORS_WHILE_COMPUTING: 'errors_while_computing_flags',
|
|
304
|
+
FLAG_MISSING: 'flag_missing',
|
|
305
|
+
QUOTA_LIMITED: 'quota_limited',
|
|
306
|
+
TIMEOUT: 'timeout',
|
|
307
|
+
CONNECTION_ERROR: 'connection_error',
|
|
308
|
+
UNKNOWN_ERROR: 'unknown_error',
|
|
309
|
+
apiError: (status: number): string => `api_error_${status}`,
|
|
310
|
+
} as const
|
|
311
|
+
|
|
312
|
+
export type FeatureFlagErrorType =
|
|
313
|
+
| (typeof FeatureFlagError)[Exclude<keyof typeof FeatureFlagError, 'apiError'>]
|
|
314
|
+
| ReturnType<typeof FeatureFlagError.apiError>
|
|
315
|
+
| string
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Represents an error that occurred during a feature flag request.
|
|
319
|
+
*/
|
|
320
|
+
export type FeatureFlagRequestError = {
|
|
321
|
+
type: 'timeout' | 'connection_error' | 'api_error' | 'unknown_error'
|
|
322
|
+
statusCode?: number
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Result type for getFlags that includes either a successful response or error information.
|
|
327
|
+
*/
|
|
328
|
+
export type GetFlagsResult =
|
|
329
|
+
| { success: true; response: PostHogFeatureFlagsResponse }
|
|
330
|
+
| { success: false; error: FeatureFlagRequestError }
|
|
331
|
+
|
|
276
332
|
export type FeatureFlagDetail = {
|
|
277
333
|
key: string
|
|
278
334
|
enabled: boolean
|
|
@@ -566,3 +622,28 @@ export const knownUnsafeEditableEvent = [
|
|
|
566
622
|
* Some features of PostHog rely on receiving 100% of these events
|
|
567
623
|
*/
|
|
568
624
|
export type KnownUnsafeEditableEvent = (typeof knownUnsafeEditableEvent)[number]
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Represents an event before it's sent to PostHog.
|
|
628
|
+
* This is the interface exposed to the `before_send` hook, matching the web SDK's `CaptureResult`.
|
|
629
|
+
*/
|
|
630
|
+
export type CaptureEvent = {
|
|
631
|
+
/** UUID for the event (optional to allow compatibility with Node SDK's EventMessage) */
|
|
632
|
+
uuid?: string
|
|
633
|
+
/** The name of the event */
|
|
634
|
+
event: string
|
|
635
|
+
/** Properties associated with the event (optional to allow compatibility with Node SDK's EventMessage) */
|
|
636
|
+
properties?: PostHogEventProperties
|
|
637
|
+
/** Properties to set on the person (overrides existing values) */
|
|
638
|
+
$set?: PostHogEventProperties
|
|
639
|
+
/** Properties to set on the person only once (does not override existing values) */
|
|
640
|
+
$set_once?: PostHogEventProperties
|
|
641
|
+
/** Timestamp for the event */
|
|
642
|
+
timestamp?: Date
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Function type for the `before_send` hook.
|
|
647
|
+
* Receives an event and can return a modified event or null to drop the event.
|
|
648
|
+
*/
|
|
649
|
+
export type BeforeSendFn = (event: CaptureEvent | null) => CaptureEvent | null
|