posthog-node 2.5.4 → 3.0.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/CHANGELOG.md +22 -0
- package/lib/index.cjs.js +196 -44
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +20 -9
- package/lib/index.esm.js +196 -44
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-core/src/index.d.ts +7 -6
- package/lib/posthog-core/src/types.d.ts +2 -0
- package/lib/posthog-node/src/feature-flags.d.ts +2 -1
- package/lib/posthog-node/src/posthog-node.d.ts +9 -3
- package/lib/posthog-node/src/types.d.ts +14 -6
- package/package.json +1 -1
- package/src/feature-flags.ts +132 -9
- package/src/posthog-node.ts +42 -17
- package/src/types.ts +16 -6
- package/test/feature-flags.spec.ts +175 -2
- package/test/posthog-node.spec.ts +177 -11
|
@@ -13,6 +13,7 @@ export declare abstract class PostHogCoreStateless {
|
|
|
13
13
|
private removeDebugCallback?;
|
|
14
14
|
private debugMode;
|
|
15
15
|
private pendingPromises;
|
|
16
|
+
private disableGeoip;
|
|
16
17
|
private _optoutOverride;
|
|
17
18
|
protected _events: SimpleEventEmitter;
|
|
18
19
|
protected _flushTimer?: any;
|
|
@@ -40,7 +41,7 @@ export declare abstract class PostHogCoreStateless {
|
|
|
40
41
|
}, options?: PosthogCaptureOptions): this;
|
|
41
42
|
protected aliasStateless(alias: string, distinctId: string, properties?: {
|
|
42
43
|
[key: string]: any;
|
|
43
|
-
}): this;
|
|
44
|
+
}, options?: PosthogCaptureOptions): this;
|
|
44
45
|
/***
|
|
45
46
|
*** GROUPS
|
|
46
47
|
***/
|
|
@@ -49,12 +50,12 @@ export declare abstract class PostHogCoreStateless {
|
|
|
49
50
|
*** FEATURE FLAGS
|
|
50
51
|
***/
|
|
51
52
|
protected getDecide(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, extraPayload?: Record<string, any>): Promise<PostHogDecideResponse | undefined>;
|
|
52
|
-
protected getFeatureFlagStateless(key: string, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string
|
|
53
|
-
protected getFeatureFlagPayloadStateless(key: string, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string
|
|
54
|
-
protected getFeatureFlagPayloadsStateless(distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string
|
|
53
|
+
protected getFeatureFlagStateless(key: string, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, disableGeoip?: boolean): Promise<boolean | string | undefined>;
|
|
54
|
+
protected getFeatureFlagPayloadStateless(key: string, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, disableGeoip?: boolean): Promise<JsonType | undefined>;
|
|
55
|
+
protected getFeatureFlagPayloadsStateless(distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, disableGeoip?: boolean): Promise<PostHogDecideResponse['featureFlagPayloads'] | undefined>;
|
|
55
56
|
protected _parsePayload(response: any): any;
|
|
56
|
-
protected getFeatureFlagsStateless(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string
|
|
57
|
-
protected getFeatureFlagsAndPayloadsStateless(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string
|
|
57
|
+
protected getFeatureFlagsStateless(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, disableGeoip?: boolean): Promise<PostHogDecideResponse['featureFlags'] | undefined>;
|
|
58
|
+
protected getFeatureFlagsAndPayloadsStateless(distinctId: string, groups?: Record<string, string | number>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>, disableGeoip?: boolean): Promise<{
|
|
58
59
|
flags: PostHogDecideResponse['featureFlags'] | undefined;
|
|
59
60
|
payloads: PostHogDecideResponse['featureFlagPayloads'] | undefined;
|
|
60
61
|
}>;
|
|
@@ -17,6 +17,7 @@ export declare type PosthogCoreOptions = {
|
|
|
17
17
|
requestTimeout?: number;
|
|
18
18
|
sessionExpirationTimeSeconds?: number;
|
|
19
19
|
captureMode?: 'json' | 'form';
|
|
20
|
+
disableGeoip?: boolean;
|
|
20
21
|
};
|
|
21
22
|
export declare enum PostHogPersistedProperty {
|
|
22
23
|
AnonymousId = "anonymous_id",
|
|
@@ -44,6 +45,7 @@ export declare type PostHogFetchOptions = {
|
|
|
44
45
|
};
|
|
45
46
|
export declare type PosthogCaptureOptions = {
|
|
46
47
|
timestamp?: Date;
|
|
48
|
+
disableGeoip?: boolean;
|
|
47
49
|
};
|
|
48
50
|
export declare type PostHogFetchResponse = {
|
|
49
51
|
status: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { FeatureFlagCondition, PostHogFeatureFlag } from './types';
|
|
2
|
+
import { FeatureFlagCondition, PostHogFeatureFlag, PropertyGroup } from './types';
|
|
3
3
|
import { JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src';
|
|
4
4
|
declare class ClientError extends Error {
|
|
5
5
|
constructor(message: string);
|
|
@@ -22,6 +22,7 @@ declare class FeatureFlagsPoller {
|
|
|
22
22
|
featureFlags: Array<PostHogFeatureFlag>;
|
|
23
23
|
featureFlagsByKey: Record<string, PostHogFeatureFlag>;
|
|
24
24
|
groupTypeMapping: Record<string, string>;
|
|
25
|
+
cohorts: Record<string, PropertyGroup>;
|
|
25
26
|
loadedSuccessfullyOnce: boolean;
|
|
26
27
|
timeout?: number;
|
|
27
28
|
host: FeatureFlagsPollerOptions['host'];
|
|
@@ -24,11 +24,12 @@ export declare class PostHog extends PostHogCoreStateless implements PostHogNode
|
|
|
24
24
|
enable(): void;
|
|
25
25
|
disable(): void;
|
|
26
26
|
debug(enabled?: boolean): void;
|
|
27
|
-
capture({ distinctId, event, properties, groups, sendFeatureFlags, timestamp }: EventMessageV1): void;
|
|
28
|
-
identify({ distinctId, properties }: IdentifyMessageV1): void;
|
|
27
|
+
capture({ distinctId, event, properties, groups, sendFeatureFlags, timestamp, disableGeoip }: EventMessageV1): void;
|
|
28
|
+
identify({ distinctId, properties, disableGeoip }: IdentifyMessageV1): void;
|
|
29
29
|
alias(data: {
|
|
30
30
|
distinctId: string;
|
|
31
31
|
alias: string;
|
|
32
|
+
disableGeoip?: boolean;
|
|
32
33
|
}): void;
|
|
33
34
|
getFeatureFlag(key: string, distinctId: string, options?: {
|
|
34
35
|
groups?: Record<string, string>;
|
|
@@ -36,6 +37,7 @@ export declare class PostHog extends PostHogCoreStateless implements PostHogNode
|
|
|
36
37
|
groupProperties?: Record<string, Record<string, string>>;
|
|
37
38
|
onlyEvaluateLocally?: boolean;
|
|
38
39
|
sendFeatureFlagEvents?: boolean;
|
|
40
|
+
disableGeoip?: boolean;
|
|
39
41
|
}): Promise<string | boolean | undefined>;
|
|
40
42
|
getFeatureFlagPayload(key: string, distinctId: string, matchValue?: string | boolean, options?: {
|
|
41
43
|
groups?: Record<string, string>;
|
|
@@ -43,6 +45,7 @@ export declare class PostHog extends PostHogCoreStateless implements PostHogNode
|
|
|
43
45
|
groupProperties?: Record<string, Record<string, string>>;
|
|
44
46
|
onlyEvaluateLocally?: boolean;
|
|
45
47
|
sendFeatureFlagEvents?: boolean;
|
|
48
|
+
disableGeoip?: boolean;
|
|
46
49
|
}): Promise<JsonType | undefined>;
|
|
47
50
|
isFeatureEnabled(key: string, distinctId: string, options?: {
|
|
48
51
|
groups?: Record<string, string>;
|
|
@@ -50,20 +53,23 @@ export declare class PostHog extends PostHogCoreStateless implements PostHogNode
|
|
|
50
53
|
groupProperties?: Record<string, Record<string, string>>;
|
|
51
54
|
onlyEvaluateLocally?: boolean;
|
|
52
55
|
sendFeatureFlagEvents?: boolean;
|
|
56
|
+
disableGeoip?: boolean;
|
|
53
57
|
}): Promise<boolean | undefined>;
|
|
54
58
|
getAllFlags(distinctId: string, options?: {
|
|
55
59
|
groups?: Record<string, string>;
|
|
56
60
|
personProperties?: Record<string, string>;
|
|
57
61
|
groupProperties?: Record<string, Record<string, string>>;
|
|
58
62
|
onlyEvaluateLocally?: boolean;
|
|
63
|
+
disableGeoip?: boolean;
|
|
59
64
|
}): Promise<Record<string, string | boolean>>;
|
|
60
65
|
getAllFlagsAndPayloads(distinctId: string, options?: {
|
|
61
66
|
groups?: Record<string, string>;
|
|
62
67
|
personProperties?: Record<string, string>;
|
|
63
68
|
groupProperties?: Record<string, Record<string, string>>;
|
|
64
69
|
onlyEvaluateLocally?: boolean;
|
|
70
|
+
disableGeoip?: boolean;
|
|
65
71
|
}): Promise<PosthogFlagsAndPayloadsResponse>;
|
|
66
|
-
groupIdentify({ groupType, groupKey, properties, distinctId }: GroupIdentifyMessage): void;
|
|
72
|
+
groupIdentify({ groupType, groupKey, properties, distinctId, disableGeoip }: GroupIdentifyMessage): void;
|
|
67
73
|
reloadFeatureFlags(): Promise<void>;
|
|
68
74
|
shutdown(): void;
|
|
69
75
|
shutdownAsync(): Promise<void>;
|
|
@@ -2,6 +2,7 @@ import { JsonType } from '../../posthog-core/src';
|
|
|
2
2
|
export interface IdentifyMessageV1 {
|
|
3
3
|
distinctId: string;
|
|
4
4
|
properties?: Record<string | number, any>;
|
|
5
|
+
disableGeoip?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export interface EventMessageV1 extends IdentifyMessageV1 {
|
|
7
8
|
event: string;
|
|
@@ -14,14 +15,21 @@ export interface GroupIdentifyMessage {
|
|
|
14
15
|
groupKey: string;
|
|
15
16
|
properties?: Record<string | number, any>;
|
|
16
17
|
distinctId?: string;
|
|
18
|
+
disableGeoip?: boolean;
|
|
17
19
|
}
|
|
20
|
+
export declare type PropertyGroup = {
|
|
21
|
+
type: 'AND' | 'OR';
|
|
22
|
+
values: PropertyGroup[] | FlagProperty[];
|
|
23
|
+
};
|
|
24
|
+
export declare type FlagProperty = {
|
|
25
|
+
key: string;
|
|
26
|
+
type?: string;
|
|
27
|
+
value: string | number | (string | number)[];
|
|
28
|
+
operator?: string;
|
|
29
|
+
negation?: boolean;
|
|
30
|
+
};
|
|
18
31
|
export declare type FeatureFlagCondition = {
|
|
19
|
-
properties:
|
|
20
|
-
key: string;
|
|
21
|
-
type?: string;
|
|
22
|
-
value: string | number | (string | number)[];
|
|
23
|
-
operator?: string;
|
|
24
|
-
}[];
|
|
32
|
+
properties: FlagProperty[];
|
|
25
33
|
rollout_percentage?: number;
|
|
26
34
|
variant?: string;
|
|
27
35
|
};
|
package/package.json
CHANGED
package/src/feature-flags.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'crypto'
|
|
2
|
-
import { FeatureFlagCondition, PostHogFeatureFlag } from './types'
|
|
2
|
+
import { FeatureFlagCondition, FlagProperty, PostHogFeatureFlag, PropertyGroup } from './types'
|
|
3
3
|
import { version } from '../package.json'
|
|
4
4
|
import { JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src'
|
|
5
5
|
import { safeSetTimeout } from 'posthog-core/src/utils'
|
|
@@ -46,6 +46,7 @@ class FeatureFlagsPoller {
|
|
|
46
46
|
featureFlags: Array<PostHogFeatureFlag>
|
|
47
47
|
featureFlagsByKey: Record<string, PostHogFeatureFlag>
|
|
48
48
|
groupTypeMapping: Record<string, string>
|
|
49
|
+
cohorts: Record<string, PropertyGroup>
|
|
49
50
|
loadedSuccessfullyOnce: boolean
|
|
50
51
|
timeout?: number
|
|
51
52
|
host: FeatureFlagsPollerOptions['host']
|
|
@@ -66,6 +67,7 @@ class FeatureFlagsPoller {
|
|
|
66
67
|
this.featureFlags = []
|
|
67
68
|
this.featureFlagsByKey = {}
|
|
68
69
|
this.groupTypeMapping = {}
|
|
70
|
+
this.cohorts = {}
|
|
69
71
|
this.loadedSuccessfullyOnce = false
|
|
70
72
|
this.timeout = timeout
|
|
71
73
|
this.projectApiKey = projectApiKey
|
|
@@ -291,13 +293,22 @@ class FeatureFlagsPoller {
|
|
|
291
293
|
const rolloutPercentage = condition.rollout_percentage
|
|
292
294
|
|
|
293
295
|
if ((condition.properties || []).length > 0) {
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
296
|
+
for (const prop of condition.properties) {
|
|
297
|
+
const propertyType = prop.type
|
|
298
|
+
let matches = false
|
|
299
|
+
|
|
300
|
+
if (propertyType === 'cohort') {
|
|
301
|
+
matches = matchCohort(prop, properties, this.cohorts)
|
|
302
|
+
} else {
|
|
303
|
+
matches = matchProperty(prop, properties)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!matches) {
|
|
307
|
+
return false
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (rolloutPercentage == undefined) {
|
|
301
312
|
return true
|
|
302
313
|
}
|
|
303
314
|
}
|
|
@@ -378,6 +389,7 @@ class FeatureFlagsPoller {
|
|
|
378
389
|
<Record<string, PostHogFeatureFlag>>{}
|
|
379
390
|
)
|
|
380
391
|
this.groupTypeMapping = responseJson.group_type_mapping || {}
|
|
392
|
+
this.cohorts = responseJson.cohorts || []
|
|
381
393
|
this.loadedSuccessfullyOnce = true
|
|
382
394
|
} catch (err) {
|
|
383
395
|
// if an error that is not an instance of ClientError is thrown
|
|
@@ -389,7 +401,7 @@ class FeatureFlagsPoller {
|
|
|
389
401
|
}
|
|
390
402
|
|
|
391
403
|
async _requestFeatureFlagDefinitions(): Promise<PostHogFetchResponse> {
|
|
392
|
-
const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}`
|
|
404
|
+
const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`
|
|
393
405
|
|
|
394
406
|
const options: PostHogFetchOptions = {
|
|
395
407
|
method: 'GET',
|
|
@@ -487,6 +499,117 @@ function matchProperty(
|
|
|
487
499
|
}
|
|
488
500
|
}
|
|
489
501
|
|
|
502
|
+
function matchCohort(
|
|
503
|
+
property: FeatureFlagCondition['properties'][number],
|
|
504
|
+
propertyValues: Record<string, any>,
|
|
505
|
+
cohortProperties: FeatureFlagsPoller['cohorts']
|
|
506
|
+
): boolean {
|
|
507
|
+
const cohortId = String(property.value)
|
|
508
|
+
if (!(cohortId in cohortProperties)) {
|
|
509
|
+
throw new InconclusiveMatchError("can't match cohort without a given cohort property value")
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const propertyGroup = cohortProperties[cohortId]
|
|
513
|
+
return matchPropertyGroup(propertyGroup, propertyValues, cohortProperties)
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function matchPropertyGroup(
|
|
517
|
+
propertyGroup: PropertyGroup,
|
|
518
|
+
propertyValues: Record<string, any>,
|
|
519
|
+
cohortProperties: FeatureFlagsPoller['cohorts']
|
|
520
|
+
): boolean {
|
|
521
|
+
if (!propertyGroup) {
|
|
522
|
+
return true
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const propertyGroupType = propertyGroup.type
|
|
526
|
+
const properties = propertyGroup.values
|
|
527
|
+
|
|
528
|
+
if (!properties || properties.length === 0) {
|
|
529
|
+
// empty groups are no-ops, always match
|
|
530
|
+
return true
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
let errorMatchingLocally = false
|
|
534
|
+
|
|
535
|
+
if ('values' in properties[0]) {
|
|
536
|
+
// a nested property group
|
|
537
|
+
for (const prop of properties as PropertyGroup[]) {
|
|
538
|
+
try {
|
|
539
|
+
const matches = matchPropertyGroup(prop, propertyValues, cohortProperties)
|
|
540
|
+
if (propertyGroupType === 'AND') {
|
|
541
|
+
if (!matches) {
|
|
542
|
+
return false
|
|
543
|
+
}
|
|
544
|
+
} else {
|
|
545
|
+
// OR group
|
|
546
|
+
if (matches) {
|
|
547
|
+
return true
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
} catch (err) {
|
|
551
|
+
if (err instanceof InconclusiveMatchError) {
|
|
552
|
+
console.debug(`Failed to compute property ${prop} locally: ${err}`)
|
|
553
|
+
errorMatchingLocally = true
|
|
554
|
+
} else {
|
|
555
|
+
throw err
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (errorMatchingLocally) {
|
|
561
|
+
throw new InconclusiveMatchError("Can't match cohort without a given cohort property value")
|
|
562
|
+
}
|
|
563
|
+
// if we get here, all matched in AND case, or none matched in OR case
|
|
564
|
+
return propertyGroupType === 'AND'
|
|
565
|
+
} else {
|
|
566
|
+
for (const prop of properties as FlagProperty[]) {
|
|
567
|
+
try {
|
|
568
|
+
let matches: boolean
|
|
569
|
+
if (prop.type === 'cohort') {
|
|
570
|
+
matches = matchCohort(prop, propertyValues, cohortProperties)
|
|
571
|
+
} else {
|
|
572
|
+
matches = matchProperty(prop, propertyValues)
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const negation = prop.negation || false
|
|
576
|
+
|
|
577
|
+
if (propertyGroupType === 'AND') {
|
|
578
|
+
// if negated property, do the inverse
|
|
579
|
+
if (!matches && !negation) {
|
|
580
|
+
return false
|
|
581
|
+
}
|
|
582
|
+
if (matches && negation) {
|
|
583
|
+
return false
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
// OR group
|
|
587
|
+
if (matches && !negation) {
|
|
588
|
+
return true
|
|
589
|
+
}
|
|
590
|
+
if (!matches && negation) {
|
|
591
|
+
return true
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
} catch (err) {
|
|
595
|
+
if (err instanceof InconclusiveMatchError) {
|
|
596
|
+
console.debug(`Failed to compute property ${prop} locally: ${err}`)
|
|
597
|
+
errorMatchingLocally = true
|
|
598
|
+
} else {
|
|
599
|
+
throw err
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (errorMatchingLocally) {
|
|
605
|
+
throw new InconclusiveMatchError("can't match cohort without a given cohort property value")
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// if we get here, all matched in AND case, or none matched in OR case
|
|
609
|
+
return propertyGroupType === 'AND'
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
490
613
|
function isValidRegex(regex: string): boolean {
|
|
491
614
|
try {
|
|
492
615
|
new RegExp(regex)
|
package/src/posthog-node.ts
CHANGED
|
@@ -97,13 +97,13 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
97
97
|
this.featureFlagsPoller?.debug(enabled)
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
capture({ distinctId, event, properties, groups, sendFeatureFlags, timestamp }: EventMessageV1): void {
|
|
100
|
+
capture({ distinctId, event, properties, groups, sendFeatureFlags, timestamp, disableGeoip }: EventMessageV1): void {
|
|
101
101
|
const _capture = (props: EventMessageV1['properties']): void => {
|
|
102
|
-
super.captureStateless(distinctId, event, props, { timestamp })
|
|
102
|
+
super.captureStateless(distinctId, event, props, { timestamp, disableGeoip })
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (sendFeatureFlags) {
|
|
106
|
-
super.getFeatureFlagsStateless(distinctId, groups).then((flags) => {
|
|
106
|
+
super.getFeatureFlagsStateless(distinctId, groups, undefined, undefined, disableGeoip).then((flags) => {
|
|
107
107
|
const featureVariantProperties: Record<string, string | boolean> = {}
|
|
108
108
|
if (flags) {
|
|
109
109
|
for (const [feature, variant] of Object.entries(flags)) {
|
|
@@ -124,17 +124,21 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
identify({ distinctId, properties }: IdentifyMessageV1): void {
|
|
127
|
+
identify({ distinctId, properties, disableGeoip }: IdentifyMessageV1): void {
|
|
128
128
|
// Catch properties passed as $set and move them to the top level
|
|
129
129
|
const personProperties = properties?.$set || properties
|
|
130
130
|
|
|
131
|
-
super.identifyStateless(
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
super.identifyStateless(
|
|
132
|
+
distinctId,
|
|
133
|
+
{
|
|
134
|
+
$set: personProperties,
|
|
135
|
+
},
|
|
136
|
+
{ disableGeoip }
|
|
137
|
+
)
|
|
134
138
|
}
|
|
135
139
|
|
|
136
|
-
alias(data: { distinctId: string; alias: string }): void {
|
|
137
|
-
super.aliasStateless(data.alias, data.distinctId)
|
|
140
|
+
alias(data: { distinctId: string; alias: string; disableGeoip?: boolean }): void {
|
|
141
|
+
super.aliasStateless(data.alias, data.distinctId, undefined, { disableGeoip: data.disableGeoip })
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
async getFeatureFlag(
|
|
@@ -146,9 +150,10 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
146
150
|
groupProperties?: Record<string, Record<string, string>>
|
|
147
151
|
onlyEvaluateLocally?: boolean
|
|
148
152
|
sendFeatureFlagEvents?: boolean
|
|
153
|
+
disableGeoip?: boolean
|
|
149
154
|
}
|
|
150
155
|
): Promise<string | boolean | undefined> {
|
|
151
|
-
const { groups, personProperties, groupProperties } = options || {}
|
|
156
|
+
const { groups, personProperties, groupProperties, disableGeoip } = options || {}
|
|
152
157
|
let { onlyEvaluateLocally, sendFeatureFlagEvents } = options || {}
|
|
153
158
|
|
|
154
159
|
// set defaults
|
|
@@ -170,7 +175,14 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
170
175
|
const flagWasLocallyEvaluated = response !== undefined
|
|
171
176
|
|
|
172
177
|
if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
|
|
173
|
-
response = await super.getFeatureFlagStateless(
|
|
178
|
+
response = await super.getFeatureFlagStateless(
|
|
179
|
+
key,
|
|
180
|
+
distinctId,
|
|
181
|
+
groups,
|
|
182
|
+
personProperties,
|
|
183
|
+
groupProperties,
|
|
184
|
+
disableGeoip
|
|
185
|
+
)
|
|
174
186
|
}
|
|
175
187
|
|
|
176
188
|
const featureFlagReportedKey = `${key}_${response}`
|
|
@@ -197,6 +209,7 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
197
209
|
locally_evaluated: flagWasLocallyEvaluated,
|
|
198
210
|
},
|
|
199
211
|
groups,
|
|
212
|
+
disableGeoip,
|
|
200
213
|
})
|
|
201
214
|
}
|
|
202
215
|
return response
|
|
@@ -212,9 +225,10 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
212
225
|
groupProperties?: Record<string, Record<string, string>>
|
|
213
226
|
onlyEvaluateLocally?: boolean
|
|
214
227
|
sendFeatureFlagEvents?: boolean
|
|
228
|
+
disableGeoip?: boolean
|
|
215
229
|
}
|
|
216
230
|
): Promise<JsonType | undefined> {
|
|
217
|
-
const { groups, personProperties, groupProperties } = options || {}
|
|
231
|
+
const { groups, personProperties, groupProperties, disableGeoip } = options || {}
|
|
218
232
|
let { onlyEvaluateLocally, sendFeatureFlagEvents } = options || {}
|
|
219
233
|
let response = undefined
|
|
220
234
|
|
|
@@ -246,7 +260,14 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
246
260
|
const payloadWasLocallyEvaluated = response !== undefined
|
|
247
261
|
|
|
248
262
|
if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
|
|
249
|
-
response = await super.getFeatureFlagPayloadStateless(
|
|
263
|
+
response = await super.getFeatureFlagPayloadStateless(
|
|
264
|
+
key,
|
|
265
|
+
distinctId,
|
|
266
|
+
groups,
|
|
267
|
+
personProperties,
|
|
268
|
+
groupProperties,
|
|
269
|
+
disableGeoip
|
|
270
|
+
)
|
|
250
271
|
}
|
|
251
272
|
|
|
252
273
|
try {
|
|
@@ -265,6 +286,7 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
265
286
|
groupProperties?: Record<string, Record<string, string>>
|
|
266
287
|
onlyEvaluateLocally?: boolean
|
|
267
288
|
sendFeatureFlagEvents?: boolean
|
|
289
|
+
disableGeoip?: boolean
|
|
268
290
|
}
|
|
269
291
|
): Promise<boolean | undefined> {
|
|
270
292
|
const feat = await this.getFeatureFlag(key, distinctId, options)
|
|
@@ -281,6 +303,7 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
281
303
|
personProperties?: Record<string, string>
|
|
282
304
|
groupProperties?: Record<string, Record<string, string>>
|
|
283
305
|
onlyEvaluateLocally?: boolean
|
|
306
|
+
disableGeoip?: boolean
|
|
284
307
|
}
|
|
285
308
|
): Promise<Record<string, string | boolean>> {
|
|
286
309
|
const response = await this.getAllFlagsAndPayloads(distinctId, options)
|
|
@@ -294,9 +317,10 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
294
317
|
personProperties?: Record<string, string>
|
|
295
318
|
groupProperties?: Record<string, Record<string, string>>
|
|
296
319
|
onlyEvaluateLocally?: boolean
|
|
320
|
+
disableGeoip?: boolean
|
|
297
321
|
}
|
|
298
322
|
): Promise<PosthogFlagsAndPayloadsResponse> {
|
|
299
|
-
const { groups, personProperties, groupProperties } = options || {}
|
|
323
|
+
const { groups, personProperties, groupProperties, disableGeoip } = options || {}
|
|
300
324
|
let { onlyEvaluateLocally } = options || {}
|
|
301
325
|
|
|
302
326
|
// set defaults
|
|
@@ -325,7 +349,8 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
325
349
|
distinctId,
|
|
326
350
|
groups,
|
|
327
351
|
personProperties,
|
|
328
|
-
groupProperties
|
|
352
|
+
groupProperties,
|
|
353
|
+
disableGeoip
|
|
329
354
|
)
|
|
330
355
|
featureFlags = {
|
|
331
356
|
...featureFlags,
|
|
@@ -340,8 +365,8 @@ export class PostHog extends PostHogCoreStateless implements PostHogNodeV1 {
|
|
|
340
365
|
return { featureFlags, featureFlagPayloads }
|
|
341
366
|
}
|
|
342
367
|
|
|
343
|
-
groupIdentify({ groupType, groupKey, properties, distinctId }: GroupIdentifyMessage): void {
|
|
344
|
-
super.groupIdentifyStateless(groupType, groupKey, properties,
|
|
368
|
+
groupIdentify({ groupType, groupKey, properties, distinctId, disableGeoip }: GroupIdentifyMessage): void {
|
|
369
|
+
super.groupIdentifyStateless(groupType, groupKey, properties, { disableGeoip }, distinctId)
|
|
345
370
|
}
|
|
346
371
|
|
|
347
372
|
async reloadFeatureFlags(): Promise<void> {
|
package/src/types.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { JsonType } from '../../posthog-core/src'
|
|
|
3
3
|
export interface IdentifyMessageV1 {
|
|
4
4
|
distinctId: string
|
|
5
5
|
properties?: Record<string | number, any>
|
|
6
|
+
disableGeoip?: boolean
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export interface EventMessageV1 extends IdentifyMessageV1 {
|
|
@@ -17,15 +18,24 @@ export interface GroupIdentifyMessage {
|
|
|
17
18
|
groupKey: string // Unique identifier for the group
|
|
18
19
|
properties?: Record<string | number, any>
|
|
19
20
|
distinctId?: string // optional distinctId to associate message with a person
|
|
21
|
+
disableGeoip?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type PropertyGroup = {
|
|
25
|
+
type: 'AND' | 'OR'
|
|
26
|
+
values: PropertyGroup[] | FlagProperty[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type FlagProperty = {
|
|
30
|
+
key: string
|
|
31
|
+
type?: string
|
|
32
|
+
value: string | number | (string | number)[]
|
|
33
|
+
operator?: string
|
|
34
|
+
negation?: boolean
|
|
20
35
|
}
|
|
21
36
|
|
|
22
37
|
export type FeatureFlagCondition = {
|
|
23
|
-
properties:
|
|
24
|
-
key: string
|
|
25
|
-
type?: string
|
|
26
|
-
value: string | number | (string | number)[]
|
|
27
|
-
operator?: string
|
|
28
|
-
}[]
|
|
38
|
+
properties: FlagProperty[]
|
|
29
39
|
rollout_percentage?: number
|
|
30
40
|
variant?: string
|
|
31
41
|
}
|