posthog-node 2.2.2 → 2.3.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 +8 -0
- package/lib/index.cjs.js +296 -30
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +60 -1
- package/lib/index.esm.js +296 -30
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-core/src/index.d.ts +9 -1
- package/lib/posthog-core/src/types.d.ts +13 -0
- package/lib/posthog-node/src/feature-flags.d.ts +5 -2
- package/lib/posthog-node/src/posthog-node.d.ts +14 -1
- package/lib/posthog-node/src/types.d.ts +19 -0
- package/package.json +1 -1
- package/src/feature-flags.ts +53 -8
- package/src/posthog-node.ts +99 -8
- package/src/types.ts +26 -0
- package/test/feature-flags.spec.ts +382 -3
- package/test/posthog-node.spec.ts +46 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PostHogFetchOptions, PostHogFetchResponse, PostHogAutocaptureElement, PostHogDecideResponse, PosthogCoreOptions, PostHogEventProperties, PostHogPersistedProperty } from './types';
|
|
1
|
+
import { PostHogFetchOptions, PostHogFetchResponse, PostHogAutocaptureElement, PostHogDecideResponse, PosthogCoreOptions, PostHogEventProperties, PostHogPersistedProperty, JsonType } from './types';
|
|
2
2
|
import { RetriableOptions } from './utils';
|
|
3
3
|
export * as utils from './utils';
|
|
4
4
|
import { LZString } from './lz-string';
|
|
@@ -79,8 +79,16 @@ export declare abstract class PostHogCore {
|
|
|
79
79
|
private decideAsync;
|
|
80
80
|
private _decideAsync;
|
|
81
81
|
private setKnownFeatureFlags;
|
|
82
|
+
private setKnownFeatureFlagPayloads;
|
|
82
83
|
getFeatureFlag(key: string): boolean | string | undefined;
|
|
84
|
+
getFeatureFlagPayload(key: string): JsonType | undefined;
|
|
85
|
+
getFeatureFlagPayloads(): PostHogDecideResponse['featureFlagPayloads'] | undefined;
|
|
86
|
+
_parsePayload(response: any): any;
|
|
83
87
|
getFeatureFlags(): PostHogDecideResponse['featureFlags'] | undefined;
|
|
88
|
+
getFeatureFlagsAndPayloads(): {
|
|
89
|
+
flags: PostHogDecideResponse['featureFlags'] | undefined;
|
|
90
|
+
payloads: PostHogDecideResponse['featureFlagPayloads'] | undefined;
|
|
91
|
+
};
|
|
84
92
|
isFeatureEnabled(key: string): boolean | undefined;
|
|
85
93
|
reloadFeatureFlagsAsync(sendAnonDistinctId?: boolean): Promise<PostHogDecideResponse['featureFlags']>;
|
|
86
94
|
onFeatureFlags(cb: (flags: PostHogDecideResponse['featureFlags']) => void): () => void;
|
|
@@ -10,6 +10,7 @@ export declare type PosthogCoreOptions = {
|
|
|
10
10
|
distinctId?: string;
|
|
11
11
|
isIdentifiedId?: boolean;
|
|
12
12
|
featureFlags?: Record<string, boolean | string>;
|
|
13
|
+
featureFlagPayloads?: Record<string, JsonType>;
|
|
13
14
|
};
|
|
14
15
|
fetchRetryCount?: number;
|
|
15
16
|
fetchRetryDelay?: number;
|
|
@@ -22,6 +23,7 @@ export declare enum PostHogPersistedProperty {
|
|
|
22
23
|
DistinctId = "distinct_id",
|
|
23
24
|
Props = "props",
|
|
24
25
|
FeatureFlags = "feature_flags",
|
|
26
|
+
FeatureFlagPayloads = "feature_flag_payloads",
|
|
25
27
|
OverrideFeatureFlags = "override_feature_flags",
|
|
26
28
|
Queue = "queue",
|
|
27
29
|
OptedOut = "opted_out",
|
|
@@ -75,5 +77,16 @@ export declare type PostHogDecideResponse = {
|
|
|
75
77
|
featureFlags: {
|
|
76
78
|
[key: string]: string | boolean;
|
|
77
79
|
};
|
|
80
|
+
featureFlagPayloads: {
|
|
81
|
+
[key: string]: JsonType;
|
|
82
|
+
};
|
|
83
|
+
errorsWhileComputingFlags: boolean;
|
|
78
84
|
sessionRecording: boolean;
|
|
79
85
|
};
|
|
86
|
+
export declare type PosthogFlagsAndPayloadsResponse = {
|
|
87
|
+
featureFlags: PostHogDecideResponse['featureFlags'];
|
|
88
|
+
featureFlagPayloads: PostHogDecideResponse['featureFlagPayloads'];
|
|
89
|
+
};
|
|
90
|
+
export declare type JsonType = string | number | boolean | null | {
|
|
91
|
+
[key: string]: JsonType;
|
|
92
|
+
} | Array<JsonType>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { FeatureFlagCondition, PostHogFeatureFlag } from './types';
|
|
3
|
-
import { PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src';
|
|
3
|
+
import { JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src';
|
|
4
4
|
declare class ClientError extends Error {
|
|
5
5
|
constructor(message: string);
|
|
6
6
|
}
|
|
@@ -20,6 +20,7 @@ declare class FeatureFlagsPoller {
|
|
|
20
20
|
personalApiKey: string;
|
|
21
21
|
projectApiKey: string;
|
|
22
22
|
featureFlags: Array<PostHogFeatureFlag>;
|
|
23
|
+
featureFlagsByKey: Record<string, PostHogFeatureFlag>;
|
|
23
24
|
groupTypeMapping: Record<string, string>;
|
|
24
25
|
loadedSuccessfullyOnce: boolean;
|
|
25
26
|
timeout?: number;
|
|
@@ -28,8 +29,10 @@ declare class FeatureFlagsPoller {
|
|
|
28
29
|
fetch: (url: string, options: PostHogFetchOptions) => Promise<PostHogFetchResponse>;
|
|
29
30
|
constructor({ pollingInterval, personalApiKey, projectApiKey, timeout, host, ...options }: FeatureFlagsPollerOptions);
|
|
30
31
|
getFeatureFlag(key: string, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): Promise<string | boolean | undefined>;
|
|
31
|
-
|
|
32
|
+
computeFeatureFlagPayloadLocally(key: string, matchValue: string | boolean): Promise<JsonType | undefined>;
|
|
33
|
+
getAllFlagsAndPayloads(distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): Promise<{
|
|
32
34
|
response: Record<string, string | boolean>;
|
|
35
|
+
payloads: Record<string, JsonType>;
|
|
33
36
|
fallbackToDecide: boolean;
|
|
34
37
|
}>;
|
|
35
38
|
computeFlagLocally(flag: PostHogFeatureFlag, distinctId: string, groups?: Record<string, string>, personProperties?: Record<string, string>, groupProperties?: Record<string, Record<string, string>>): string | boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PosthogCoreOptions, PostHogFetchOptions, PostHogFetchResponse } from '../../posthog-core/src';
|
|
1
|
+
import { JsonType, PosthogCoreOptions, PostHogFetchOptions, PostHogFetchResponse, PosthogFlagsAndPayloadsResponse } from '../../posthog-core/src';
|
|
2
2
|
import { EventMessageV1, GroupIdentifyMessage, IdentifyMessageV1, PostHogNodeV1 } from './types';
|
|
3
3
|
export declare type PostHogOptions = PosthogCoreOptions & {
|
|
4
4
|
persistence?: 'memory';
|
|
@@ -30,6 +30,13 @@ export declare class PostHog implements PostHogNodeV1 {
|
|
|
30
30
|
onlyEvaluateLocally?: boolean;
|
|
31
31
|
sendFeatureFlagEvents?: boolean;
|
|
32
32
|
}): Promise<string | boolean | undefined>;
|
|
33
|
+
getFeatureFlagPayload(key: string, distinctId: string, matchValue?: string | boolean, options?: {
|
|
34
|
+
groups?: Record<string, string>;
|
|
35
|
+
personProperties?: Record<string, string>;
|
|
36
|
+
groupProperties?: Record<string, Record<string, string>>;
|
|
37
|
+
onlyEvaluateLocally?: boolean;
|
|
38
|
+
sendFeatureFlagEvents?: boolean;
|
|
39
|
+
}): Promise<JsonType | undefined>;
|
|
33
40
|
isFeatureEnabled(key: string, distinctId: string, options?: {
|
|
34
41
|
groups?: Record<string, string>;
|
|
35
42
|
personProperties?: Record<string, string>;
|
|
@@ -43,6 +50,12 @@ export declare class PostHog implements PostHogNodeV1 {
|
|
|
43
50
|
groupProperties?: Record<string, Record<string, string>>;
|
|
44
51
|
onlyEvaluateLocally?: boolean;
|
|
45
52
|
}): Promise<Record<string, string | boolean>>;
|
|
53
|
+
getAllFlagsAndPayloads(distinctId: string, options?: {
|
|
54
|
+
groups?: Record<string, string>;
|
|
55
|
+
personProperties?: Record<string, string>;
|
|
56
|
+
groupProperties?: Record<string, Record<string, string>>;
|
|
57
|
+
onlyEvaluateLocally?: boolean;
|
|
58
|
+
}): Promise<PosthogFlagsAndPayloadsResponse>;
|
|
46
59
|
groupIdentify({ groupType, groupKey, properties }: GroupIdentifyMessage): void;
|
|
47
60
|
reloadFeatureFlags(): Promise<void>;
|
|
48
61
|
flush(): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JsonType } from 'posthog-core/src';
|
|
1
2
|
export interface IdentifyMessageV1 {
|
|
2
3
|
distinctId: string;
|
|
3
4
|
properties?: Record<string | number, any>;
|
|
@@ -35,6 +36,7 @@ export declare type PostHogFeatureFlag = {
|
|
|
35
36
|
rollout_percentage: number;
|
|
36
37
|
}[];
|
|
37
38
|
};
|
|
39
|
+
payloads?: Record<string, JsonType>;
|
|
38
40
|
};
|
|
39
41
|
deleted: boolean;
|
|
40
42
|
active: boolean;
|
|
@@ -125,6 +127,23 @@ export declare type PostHogNodeV1 = {
|
|
|
125
127
|
onlyEvaluateLocally?: boolean;
|
|
126
128
|
sendFeatureFlagEvents?: boolean;
|
|
127
129
|
}): Promise<string | boolean | undefined>;
|
|
130
|
+
/**
|
|
131
|
+
* @description Retrieves payload associated with the specified flag and matched value that is passed in.
|
|
132
|
+
* (Expected to be used in conjuction with getFeatureFlag but allows for manual lookup).
|
|
133
|
+
* If matchValue isn't passed, getFeatureFlag is called implicitly.
|
|
134
|
+
* Will try to evaluate for payload locally first otherwise default to network call if allowed
|
|
135
|
+
*
|
|
136
|
+
* @param key the unique key of your feature flag
|
|
137
|
+
* @param distinctId the current unique id
|
|
138
|
+
* @param matchValue optional- the matched flag string or boolean
|
|
139
|
+
* @param options: dict with optional parameters below
|
|
140
|
+
* @param onlyEvaluateLocally optional - whether to only evaluate the flag locally. Defaults to false.
|
|
141
|
+
*
|
|
142
|
+
* @returns payload of a json type object
|
|
143
|
+
*/
|
|
144
|
+
getFeatureFlagPayload(key: string, distinctId: string, matchValue?: string | boolean, options?: {
|
|
145
|
+
onlyEvaluateLocally?: boolean;
|
|
146
|
+
}): Promise<JsonType | undefined>;
|
|
128
147
|
/**
|
|
129
148
|
* @description Sets a groups properties, which allows asking questions like "Who are the most active companies"
|
|
130
149
|
* using my product in PostHog.
|
package/package.json
CHANGED
package/src/feature-flags.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'crypto'
|
|
2
2
|
import { FeatureFlagCondition, PostHogFeatureFlag } from './types'
|
|
3
3
|
import { version } from '../package.json'
|
|
4
|
-
import { PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src'
|
|
4
|
+
import { JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src'
|
|
5
5
|
import { safeSetTimeout } from 'posthog-core/src/utils'
|
|
6
6
|
import { fetch } from './fetch'
|
|
7
7
|
|
|
@@ -44,6 +44,7 @@ class FeatureFlagsPoller {
|
|
|
44
44
|
personalApiKey: string
|
|
45
45
|
projectApiKey: string
|
|
46
46
|
featureFlags: Array<PostHogFeatureFlag>
|
|
47
|
+
featureFlagsByKey: Record<string, PostHogFeatureFlag>
|
|
47
48
|
groupTypeMapping: Record<string, string>
|
|
48
49
|
loadedSuccessfullyOnce: boolean
|
|
49
50
|
timeout?: number
|
|
@@ -62,6 +63,7 @@ class FeatureFlagsPoller {
|
|
|
62
63
|
this.pollingInterval = pollingInterval
|
|
63
64
|
this.personalApiKey = personalApiKey
|
|
64
65
|
this.featureFlags = []
|
|
66
|
+
this.featureFlagsByKey = {}
|
|
65
67
|
this.groupTypeMapping = {}
|
|
66
68
|
this.loadedSuccessfullyOnce = false
|
|
67
69
|
this.timeout = timeout
|
|
@@ -100,10 +102,9 @@ class FeatureFlagsPoller {
|
|
|
100
102
|
if (featureFlag !== undefined) {
|
|
101
103
|
try {
|
|
102
104
|
response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties)
|
|
103
|
-
console.debug(`Successfully computed flag locally: ${key} -> ${response}`)
|
|
104
105
|
} catch (e) {
|
|
105
106
|
if (e instanceof InconclusiveMatchError) {
|
|
106
|
-
console.
|
|
107
|
+
console.error(`InconclusiveMatchError when computing flag locally: ${key}: ${e}`)
|
|
107
108
|
} else if (e instanceof Error) {
|
|
108
109
|
console.error(`Error computing flag locally: ${key}: ${e}`)
|
|
109
110
|
}
|
|
@@ -113,20 +114,53 @@ class FeatureFlagsPoller {
|
|
|
113
114
|
return response
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
async
|
|
117
|
+
async computeFeatureFlagPayloadLocally(key: string, matchValue: string | boolean): Promise<JsonType | undefined> {
|
|
118
|
+
await this.loadFeatureFlags()
|
|
119
|
+
|
|
120
|
+
let response = undefined
|
|
121
|
+
|
|
122
|
+
if (!this.loadedSuccessfullyOnce) {
|
|
123
|
+
return undefined
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (typeof matchValue == 'boolean') {
|
|
127
|
+
response = this.featureFlagsByKey?.[key]?.filters?.payloads?.[matchValue.toString()]
|
|
128
|
+
} else if (typeof matchValue == 'string') {
|
|
129
|
+
response = this.featureFlagsByKey?.[key]?.filters?.payloads?.[matchValue]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
|
|
133
|
+
if (response === undefined) {
|
|
134
|
+
return null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return response
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async getAllFlagsAndPayloads(
|
|
117
141
|
distinctId: string,
|
|
118
142
|
groups: Record<string, string> = {},
|
|
119
143
|
personProperties: Record<string, string> = {},
|
|
120
144
|
groupProperties: Record<string, Record<string, string>> = {}
|
|
121
|
-
): Promise<{
|
|
145
|
+
): Promise<{
|
|
146
|
+
response: Record<string, string | boolean>
|
|
147
|
+
payloads: Record<string, JsonType>
|
|
148
|
+
fallbackToDecide: boolean
|
|
149
|
+
}> {
|
|
122
150
|
await this.loadFeatureFlags()
|
|
123
151
|
|
|
124
152
|
const response: Record<string, string | boolean> = {}
|
|
153
|
+
const payloads: Record<string, JsonType> = {}
|
|
125
154
|
let fallbackToDecide = this.featureFlags.length == 0
|
|
126
155
|
|
|
127
|
-
this.featureFlags.map((flag) => {
|
|
156
|
+
this.featureFlags.map(async (flag) => {
|
|
128
157
|
try {
|
|
129
|
-
|
|
158
|
+
const matchValue = this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties)
|
|
159
|
+
response[flag.key] = matchValue
|
|
160
|
+
const matchPayload = await this.computeFeatureFlagPayloadLocally(flag.key, matchValue)
|
|
161
|
+
if (matchPayload) {
|
|
162
|
+
payloads[flag.key] = matchPayload
|
|
163
|
+
}
|
|
130
164
|
} catch (e) {
|
|
131
165
|
if (e instanceof InconclusiveMatchError) {
|
|
132
166
|
// do nothing
|
|
@@ -137,7 +171,7 @@ class FeatureFlagsPoller {
|
|
|
137
171
|
}
|
|
138
172
|
})
|
|
139
173
|
|
|
140
|
-
return { response, fallbackToDecide }
|
|
174
|
+
return { response, payloads, fallbackToDecide }
|
|
141
175
|
}
|
|
142
176
|
|
|
143
177
|
computeFlagLocally(
|
|
@@ -316,12 +350,23 @@ class FeatureFlagsPoller {
|
|
|
316
350
|
`Your personalApiKey is invalid. Are you sure you're not using your Project API key? More information: https://posthog.com/docs/api/overview`
|
|
317
351
|
)
|
|
318
352
|
}
|
|
353
|
+
|
|
354
|
+
if (res && res.status !== 200) {
|
|
355
|
+
// something else went wrong, or the server is down.
|
|
356
|
+
// In this case, don't override existing flags
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
|
|
319
360
|
const responseJson = await res.json()
|
|
320
361
|
if (!('flags' in responseJson)) {
|
|
321
362
|
console.error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`)
|
|
322
363
|
}
|
|
323
364
|
|
|
324
365
|
this.featureFlags = responseJson.flags || []
|
|
366
|
+
this.featureFlagsByKey = this.featureFlags.reduce(
|
|
367
|
+
(acc, curr) => ((acc[curr.key] = curr), acc),
|
|
368
|
+
<Record<string, PostHogFeatureFlag>>{}
|
|
369
|
+
)
|
|
325
370
|
this.groupTypeMapping = responseJson.group_type_mapping || {}
|
|
326
371
|
this.loadedSuccessfullyOnce = true
|
|
327
372
|
} catch (err) {
|
package/src/posthog-node.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { version } from '../package.json'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
JsonType,
|
|
4
5
|
PostHogCore,
|
|
5
6
|
PosthogCoreOptions,
|
|
6
7
|
PostHogFetchOptions,
|
|
7
8
|
PostHogFetchResponse,
|
|
9
|
+
PosthogFlagsAndPayloadsResponse,
|
|
8
10
|
PostHogPersistedProperty,
|
|
9
11
|
} from '../../posthog-core/src'
|
|
10
12
|
import { PostHogMemoryStorage } from '../../posthog-core/src/storage-memory'
|
|
@@ -84,7 +86,7 @@ export class PostHog implements PostHogNodeV1 {
|
|
|
84
86
|
: THIRTY_SECONDS,
|
|
85
87
|
personalApiKey: options.personalApiKey,
|
|
86
88
|
projectApiKey: apiKey,
|
|
87
|
-
timeout: options.requestTimeout ?? 10
|
|
89
|
+
timeout: options.requestTimeout ?? 10000, // 10 seconds
|
|
88
90
|
host: this._sharedClient.host,
|
|
89
91
|
fetch: options.fetch,
|
|
90
92
|
})
|
|
@@ -203,6 +205,73 @@ export class PostHog implements PostHogNodeV1 {
|
|
|
203
205
|
return response
|
|
204
206
|
}
|
|
205
207
|
|
|
208
|
+
async getFeatureFlagPayload(
|
|
209
|
+
key: string,
|
|
210
|
+
distinctId: string,
|
|
211
|
+
matchValue?: string | boolean,
|
|
212
|
+
options?: {
|
|
213
|
+
groups?: Record<string, string>
|
|
214
|
+
personProperties?: Record<string, string>
|
|
215
|
+
groupProperties?: Record<string, Record<string, string>>
|
|
216
|
+
onlyEvaluateLocally?: boolean
|
|
217
|
+
sendFeatureFlagEvents?: boolean
|
|
218
|
+
}
|
|
219
|
+
): Promise<JsonType | undefined> {
|
|
220
|
+
const { groups, personProperties, groupProperties } = options || {}
|
|
221
|
+
let { onlyEvaluateLocally, sendFeatureFlagEvents } = options || {}
|
|
222
|
+
let response = undefined
|
|
223
|
+
|
|
224
|
+
// Try to get match value locally if not provided
|
|
225
|
+
if (!matchValue) {
|
|
226
|
+
matchValue = await this.getFeatureFlag(key, distinctId, {
|
|
227
|
+
...options,
|
|
228
|
+
onlyEvaluateLocally: true,
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (matchValue) {
|
|
233
|
+
response = await this.featureFlagsPoller?.computeFeatureFlagPayloadLocally(key, matchValue)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// set defaults
|
|
237
|
+
if (onlyEvaluateLocally == undefined) {
|
|
238
|
+
onlyEvaluateLocally = false
|
|
239
|
+
}
|
|
240
|
+
if (sendFeatureFlagEvents == undefined) {
|
|
241
|
+
sendFeatureFlagEvents = true
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// set defaults
|
|
245
|
+
if (onlyEvaluateLocally == undefined) {
|
|
246
|
+
onlyEvaluateLocally = false
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const payloadWasLocallyEvaluated = response !== undefined
|
|
250
|
+
|
|
251
|
+
if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
|
|
252
|
+
this.reInit(distinctId)
|
|
253
|
+
if (groups != undefined) {
|
|
254
|
+
this._sharedClient.groups(groups)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (personProperties) {
|
|
258
|
+
this._sharedClient.personProperties(personProperties)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (groupProperties) {
|
|
262
|
+
this._sharedClient.groupProperties(groupProperties)
|
|
263
|
+
}
|
|
264
|
+
await this._sharedClient.reloadFeatureFlagsAsync(false)
|
|
265
|
+
response = this._sharedClient.getFeatureFlagPayload(key)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
return JSON.parse(response as any)
|
|
270
|
+
} catch {
|
|
271
|
+
return response
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
206
275
|
async isFeatureEnabled(
|
|
207
276
|
key: string,
|
|
208
277
|
distinctId: string,
|
|
@@ -230,6 +299,19 @@ export class PostHog implements PostHogNodeV1 {
|
|
|
230
299
|
onlyEvaluateLocally?: boolean
|
|
231
300
|
}
|
|
232
301
|
): Promise<Record<string, string | boolean>> {
|
|
302
|
+
const response = await this.getAllFlagsAndPayloads(distinctId, options)
|
|
303
|
+
return response.featureFlags
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async getAllFlagsAndPayloads(
|
|
307
|
+
distinctId: string,
|
|
308
|
+
options?: {
|
|
309
|
+
groups?: Record<string, string>
|
|
310
|
+
personProperties?: Record<string, string>
|
|
311
|
+
groupProperties?: Record<string, Record<string, string>>
|
|
312
|
+
onlyEvaluateLocally?: boolean
|
|
313
|
+
}
|
|
314
|
+
): Promise<PosthogFlagsAndPayloadsResponse> {
|
|
233
315
|
const { groups, personProperties, groupProperties } = options || {}
|
|
234
316
|
let { onlyEvaluateLocally } = options || {}
|
|
235
317
|
|
|
@@ -238,17 +320,19 @@ export class PostHog implements PostHogNodeV1 {
|
|
|
238
320
|
onlyEvaluateLocally = false
|
|
239
321
|
}
|
|
240
322
|
|
|
241
|
-
const localEvaluationResult = await this.featureFlagsPoller?.
|
|
323
|
+
const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(
|
|
242
324
|
distinctId,
|
|
243
325
|
groups,
|
|
244
326
|
personProperties,
|
|
245
327
|
groupProperties
|
|
246
328
|
)
|
|
247
329
|
|
|
248
|
-
let
|
|
330
|
+
let featureFlags = {}
|
|
331
|
+
let featureFlagPayloads = {}
|
|
249
332
|
let fallbackToDecide = true
|
|
250
333
|
if (localEvaluationResult) {
|
|
251
|
-
|
|
334
|
+
featureFlags = localEvaluationResult.response
|
|
335
|
+
featureFlagPayloads = localEvaluationResult.payloads
|
|
252
336
|
fallbackToDecide = localEvaluationResult.fallbackToDecide
|
|
253
337
|
}
|
|
254
338
|
|
|
@@ -266,15 +350,22 @@ export class PostHog implements PostHogNodeV1 {
|
|
|
266
350
|
this._sharedClient.groupProperties(groupProperties)
|
|
267
351
|
}
|
|
268
352
|
await this._sharedClient.reloadFeatureFlagsAsync(false)
|
|
269
|
-
const remoteEvaluationResult = this._sharedClient.
|
|
270
|
-
|
|
271
|
-
|
|
353
|
+
const remoteEvaluationResult = this._sharedClient.getFeatureFlagsAndPayloads()
|
|
354
|
+
featureFlags = {
|
|
355
|
+
...featureFlags,
|
|
356
|
+
...(remoteEvaluationResult.flags || {}),
|
|
357
|
+
}
|
|
358
|
+
featureFlagPayloads = {
|
|
359
|
+
...featureFlagPayloads,
|
|
360
|
+
...(remoteEvaluationResult.payloads || {}),
|
|
361
|
+
}
|
|
272
362
|
}
|
|
273
363
|
|
|
274
|
-
return
|
|
364
|
+
return { featureFlags, featureFlagPayloads }
|
|
275
365
|
}
|
|
276
366
|
|
|
277
367
|
groupIdentify({ groupType, groupKey, properties }: GroupIdentifyMessage): void {
|
|
368
|
+
this.reInit(`$${groupType}_${groupKey}`)
|
|
278
369
|
this._sharedClient.groupIdentify(groupType, groupKey, properties)
|
|
279
370
|
}
|
|
280
371
|
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { JsonType } from 'posthog-core/src'
|
|
2
|
+
|
|
1
3
|
export interface IdentifyMessageV1 {
|
|
2
4
|
distinctId: string
|
|
3
5
|
properties?: Record<string | number, any>
|
|
@@ -39,6 +41,7 @@ export type PostHogFeatureFlag = {
|
|
|
39
41
|
rollout_percentage: number
|
|
40
42
|
}[]
|
|
41
43
|
}
|
|
44
|
+
payloads?: Record<string, JsonType>
|
|
42
45
|
}
|
|
43
46
|
deleted: boolean
|
|
44
47
|
active: boolean
|
|
@@ -140,6 +143,29 @@ export type PostHogNodeV1 = {
|
|
|
140
143
|
}
|
|
141
144
|
): Promise<string | boolean | undefined>
|
|
142
145
|
|
|
146
|
+
/**
|
|
147
|
+
* @description Retrieves payload associated with the specified flag and matched value that is passed in.
|
|
148
|
+
* (Expected to be used in conjuction with getFeatureFlag but allows for manual lookup).
|
|
149
|
+
* If matchValue isn't passed, getFeatureFlag is called implicitly.
|
|
150
|
+
* Will try to evaluate for payload locally first otherwise default to network call if allowed
|
|
151
|
+
*
|
|
152
|
+
* @param key the unique key of your feature flag
|
|
153
|
+
* @param distinctId the current unique id
|
|
154
|
+
* @param matchValue optional- the matched flag string or boolean
|
|
155
|
+
* @param options: dict with optional parameters below
|
|
156
|
+
* @param onlyEvaluateLocally optional - whether to only evaluate the flag locally. Defaults to false.
|
|
157
|
+
*
|
|
158
|
+
* @returns payload of a json type object
|
|
159
|
+
*/
|
|
160
|
+
getFeatureFlagPayload(
|
|
161
|
+
key: string,
|
|
162
|
+
distinctId: string,
|
|
163
|
+
matchValue?: string | boolean,
|
|
164
|
+
options?: {
|
|
165
|
+
onlyEvaluateLocally?: boolean
|
|
166
|
+
}
|
|
167
|
+
): Promise<JsonType | undefined>
|
|
168
|
+
|
|
143
169
|
/**
|
|
144
170
|
* @description Sets a groups properties, which allows asking questions like "Who are the most active companies"
|
|
145
171
|
* using my product in PostHog.
|